国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Sudo堆溢出漏洞(CVE-2021-3156)復(fù)現(xiàn)

這篇具有很好參考價(jià)值的文章主要介紹了Sudo堆溢出漏洞(CVE-2021-3156)復(fù)現(xiàn)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

背景介紹

2021 年 1 月 26 日,Qualys Research Labs在 sudo 發(fā)現(xiàn)了一個(gè)缺陷。sudo 解析命令行參數(shù)的方式時(shí),錯(cuò)誤的判斷了截?cái)喾?,從而?dǎo)致攻擊者可以惡意構(gòu)造載荷,使得sudo發(fā)生堆溢出,該漏洞在配合環(huán)境變量等分配堆以及釋放堆的原語(yǔ)下,可以致使本地提權(quán)。

環(huán)境搭建

環(huán)境版本

? ubuntu 20.04

? sudo-1.8.31p2

采用下述命令進(jìn)行編譯安裝

cd ./sudo-SUDO_1_8_31p2
 mkdir build
 ./configure --prefix=/home/pwn/sudo CFLAGS=”-O0 -g"
 make && make install

漏洞驗(yàn)證

#poc
./sudoedit -s '\' 11111111111111111111111111111111111111111111111111111111111111111111

執(zhí)行上述POC執(zhí)行sudoedit會(huì)出現(xiàn)malloc():invalid size的字樣,這是典型的堆溢出后導(dǎo)致的異常。

漏洞分析

源碼分析

set_cmnd函數(shù)
File: plugins\sudoers\sudoers.c
800: static int
801: set_cmnd(void)
802: {
 ?          ...
819: ? ? if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { //需要滿足標(biāo)志位的設(shè)置才能進(jìn)入轉(zhuǎn)義的流程
 ?          ...
845: 
846:    /* set user_args */
847:    if (NewArgc > 1) {
848:     ? ?char *to, *from, **av;
849:     ? ?size_t size, n;
850: 
851:     ? ?/* Alloc and build up user_args. */
852:     ? ?for (size = 0, av = NewArgv + 1; *av; av++) //遍歷每一個(gè)參數(shù)
853:        size += strlen(*av) + 1; //計(jì)算每一個(gè)參數(shù)的長(zhǎng)度
854:     ? ?if (size == 0 || (user_args = malloc(size)) == NULL) { //通過(guò)malloc動(dòng)態(tài)分配一段內(nèi)存,用于存放參數(shù)內(nèi)容
855:        sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
856:        debug_return_int(-1);
857:     ?  }
858:     ? ?if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { //需要滿足標(biāo)志位的設(shè)置才能進(jìn)入轉(zhuǎn)義的流程
859:        /*
860:         * When running a command via a shell, the sudo front-end
861:         * escapes potential meta chars.  We unescape non-spaces
862:         * for sudoers matching and logging purposes.
863:         */
864:        for (to = user_args, av = NewArgv + 1; (from = *av); av++) { //遍歷每個(gè)環(huán)境變量,并將內(nèi)容拷貝到內(nèi)存中
865:         ? ?while (*from) {
 ?              /*
 ?                  漏洞點(diǎn),當(dāng)掃描參數(shù)內(nèi)容時(shí),遇到\需要進(jìn)行轉(zhuǎn)義處理,例如'\t'、'\n'等,因此sudo只判斷\后是否跟隨著空格字符,即用isspace函數(shù)進(jìn)行判                    斷。                     
 ?                  isspace包括的字符如下:
 ?                  ' ' ? ? (0x20) ?  space (SPC) 空格符
                    '\t' ?  (0x09) ?  horizontal tab (TAB) 水平制表符 ? ?
                    '\n' ?  (0x0a) ?  newline (LF) 換行符
                    '\v' ?  (0x0b) ?  vertical tab (VT) 垂直制表符
                    '\f' ?  (0x0c) ?  feed (FF) 換頁(yè)符
                    '\r' ?  (0x0d) ?  carriage return (CR) 回車符
                    以上不包括'\0'。
                    而參數(shù)之間是使用'\0'作為分隔符的,因此當(dāng)'\\'后跟隨的'\0'會(huì)使得from++從而導(dǎo)致將后一個(gè)參數(shù)也被拷貝進(jìn)來(lái),最后致使堆塊溢出。
 ?              */
866:            if (from[0] == '\\' && !isspace((unsigned char)from[1])) 
867:             ? ?from++;
868:            *to++ = *from++;
869:         ?  }
870:         ? ?*to++ = ' ';
871:        }
872:        *--to = '\0';
?

使用POC的例子對(duì)漏洞進(jìn)行說(shuō)明

漏洞原理圖

【----幫助網(wǎng)安學(xué)習(xí),以下所有學(xué)習(xí)資料免費(fèi)領(lǐng)!加vx:yj009991,備注 “博客園” 獲??!】

 ① 網(wǎng)安學(xué)習(xí)成長(zhǎng)路徑思維導(dǎo)圖
?、?60+網(wǎng)安經(jīng)典常用工具包
 ③ 100+SRC漏洞分析報(bào)告
?、?150+網(wǎng)安攻防實(shí)戰(zhàn)技術(shù)電子書(shū)
 ⑤ 最權(quán)威CISSP 認(rèn)證考試指南+題庫(kù)
?、?超1800頁(yè)CTF實(shí)戰(zhàn)技巧手冊(cè)
?、?最新網(wǎng)安大廠面試題合集(含答案)
?、?APP客戶端安全檢測(cè)指南(安卓+IOS)

因此漏洞點(diǎn)在于在進(jìn)入set_cmnd函數(shù)時(shí)需要對(duì)轉(zhuǎn)義字符進(jìn)行轉(zhuǎn)義,但是函數(shù)卻沒(méi)有判斷轉(zhuǎn)義字符作為參數(shù)末尾的情況,即\ + \x00

parse_args函數(shù)

parse_args函數(shù)用于反轉(zhuǎn)義,即參數(shù)中若存在轉(zhuǎn)義字符,會(huì)在每個(gè)轉(zhuǎn)義字符之前增加一個(gè)\

File: src\parse_args.c
592: ? ? if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { //需要滿足標(biāo)志位的設(shè)置才會(huì)進(jìn)入反轉(zhuǎn)義流程
593:    char **av, *cmnd = NULL;
594:    int ac = 1;
595: 
596:    if (argc != 0) {
597:     ? ?/* shell -c "command" */
598:     ? ?char *src, *dst;
599:     ? ?size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
600:        strlen(argv[argc - 1]) + 1;
601: 
602:     ? ?cmnd = dst = reallocarray(NULL, cmnd_size, 2);
603:     ? ?if (cmnd == NULL)
604:        sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
605:     ? ?if (!gc_add(GC_PTR, cmnd))
606:        exit(1);
607: 
608:     ? ?for (av = argv; *av != NULL; av++) {
609:        for (src = *av; *src != '\0'; src++) {
610:         ? ?/* quote potential meta characters */
611:         ? ?if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
612:            *dst++ = '\\';
613:         ? ?*dst++ = *src;
614:        }
615:        *dst++ = ' ';
616:     ?  }
617:     ? ?if (cmnd != dst)
618:        dst--; ?/* replace last space with a NUL */
619:     ? ?*dst = '\0';
620: 
621:     ? ?ac += 2; /* -c cmnd */
622:    }
?

這也是為什么set_cmnd函數(shù)需要對(duì)參數(shù)進(jìn)行轉(zhuǎn)義,因此若先經(jīng)過(guò)parse_args函數(shù)進(jìn)行反轉(zhuǎn)義,后經(jīng)過(guò)set_cmnd函數(shù)進(jìn)行轉(zhuǎn)義,那么sudo是不會(huì)出現(xiàn)漏洞情況的

繞過(guò)檢驗(yàn)

那么如何繞過(guò)set_cmnd函數(shù)直接進(jìn)入parse_args函數(shù),才是漏洞能夠被成功觸發(fā)的關(guān)鍵因素

首先是如何才能過(guò)進(jìn)入set_cmnd函數(shù),sudo會(huì)經(jīng)過(guò)兩重檢測(cè)

  1. sudo_mode需要具有MODE_RUN、MODE_EDIT或者M(jìn)ODE_CHECK的標(biāo)志位

  2. sudo_mode需要具有MODE_SHELL或者M(jìn)ODE_LOGIN_SHELL的標(biāo)志位

File: plugins\sudoers\sudoers.c
            ...
819: ? ? if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { //需要滿足標(biāo)志位的設(shè)置才能進(jìn)入轉(zhuǎn)義的流程
 ?          ...
858:     ? ?if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { //需要滿足標(biāo)志位的設(shè)置才能進(jìn)入轉(zhuǎn)義的流程
想要獲得MODE_SHELL的標(biāo)志位,則需要設(shè)置-s參數(shù),此時(shí)通過(guò) SET(flags, MODE_SHELL),將flag設(shè)置上MODE_SHELL,并且默認(rèn)的mode是為NULL,因此設(shè)置-s參數(shù)可以使得flag即設(shè)置MODE_SHELL又設(shè)置MODE_RUN。
File: src\parse_args.c
479:        case 's':
480:         ? ?sudo_settings[ARG_USER_SHELL].value = "true";
481:         ? ?SET(flags, MODE_SHELL);
482:         ? ?break;
            ...
534:    if (!mode)
535:     ? ?mode = MODE_RUN;        /* running a command */
536: ? ? }

但是若使用sudo -s,那么就會(huì)導(dǎo)致flag即設(shè)置MODE_SHELL又設(shè)置MODE_RUN,就會(huì)進(jìn)入parse_args函數(shù)的流程,該流程會(huì)把所有非字母數(shù)字的字符前方增加一個(gè)'\',那么就會(huì)導(dǎo)致我們無(wú)法構(gòu)造'' + '\x00'的漏洞字符,因此想要漏洞利用成功,我們不需要程序進(jìn)入set_cmd函數(shù),但是不能進(jìn)入parse_args函數(shù)

File: src\parse_args.c
592: ? ? if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { //需要滿足標(biāo)志位的設(shè)置才會(huì)進(jìn)入反轉(zhuǎn)義流程
 ?          ...
608:     ? ?for (av = argv; *av != NULL; av++) {
609:        for (src = *av; *src != '\0'; src++) {
610:         ? ?/* quote potential meta characters */
611:         ? ?if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
612:            *dst++ = '\\';
613:         ? ?*dst++ = *src;
614:        }
 ?          ...
622:    }

在parse_args函數(shù)的開(kāi)頭,會(huì)檢測(cè)是以sudo還是以sudoedit進(jìn)行調(diào)用,若使用sudoedit調(diào)用,那么會(huì)直接給mode設(shè)置上MODE_EDIT,從而繞過(guò)了mode==NULL時(shí),需要將flag設(shè)置為MODE_RUN,因此使用sudoedit -s,可以使得flag即設(shè)置MODE_EDIT又設(shè)置MODE_SHELL

File: src\parse_args.c
 ?      ...
265: ? ? proglen = strlen(progname);
266: ? ? if (proglen > 4 && strcmp(progname + proglen - 4, "edit") == 0) {
267:    progname = "sudoedit";
268:    mode = MODE_EDIT;
269:    sudo_settings[ARG_SUDOEDIT].value = "true";
270: ? ? }

想要進(jìn)入set_cmnd第二條路徑就是flag設(shè)置為MODE_EDIT | MODE_SHELL,這樣的輸入就能夠繞過(guò)parse_args函數(shù)而禁止進(jìn)入set_cmd函數(shù),這也是為什么sudo的堆溢出,需要使用sudoedit -s觸發(fā),而不是sudo -s

File: plugins\sudoers\sudoers.c
            ...
819: ? ? if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { //需要滿足標(biāo)志位的設(shè)置才能進(jìn)入轉(zhuǎn)義的流程
 ?          ...
858:     ? ?if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { //需要滿足標(biāo)志位的設(shè)置才能進(jìn)入轉(zhuǎn)義的流程

漏洞利用

漏洞利用分析

由于程序存在一個(gè)明顯的堆溢出漏洞,因此需要梳理一下堆溢出如何進(jìn)行利用。

? 找到一個(gè)堆塊,該堆塊的值會(huì)影響程序執(zhí)行的流程,這里稱之為可利用堆塊。

? 找到可以隨意控制堆塊位置的操作,將漏洞函數(shù)申請(qǐng)的堆塊部署在可利用堆塊的上方,當(dāng)堆溢出觸發(fā)時(shí),可以將可利用堆塊的值被改寫成我們預(yù)期的值。

可利用堆塊

nss是用于解析和獲取不同類型的名稱信息,例如如何通過(guò)用名稱去獲取用戶信息,在sudo需要獲取用戶信息時(shí)則需要調(diào)用nss。

在使用nss去獲取信息時(shí),其實(shí)是通過(guò)不同的動(dòng)態(tài)鏈接庫(kù)去執(zhí)行相應(yīng)的行為,而這些庫(kù)的文件名則存在于/etc/nsswitch.conf的配置文件中

例如想要查詢passwd文件則需要用到libnss_files.so與libnss_systemed.so

那么如何加載這些動(dòng)態(tài)鏈接庫(kù)則需要依賴于nss_load_library函數(shù),而且這些相關(guān)信息都被存放在service_user結(jié)構(gòu)體中,而該結(jié)構(gòu)體是存放在堆內(nèi)存中的。

接著得先研究該結(jié)構(gòu)體的值是否會(huì)影響程序的執(zhí)行流程,代碼如下。

File: nsswitch.c
327: static int
328: nss_load_library (service_user *ni)
329: {
330: ? if (ni->library == NULL) 
331: ? ? {
332: ? ? ? /* This service has not yet been used.  Fetch the service
333:     library for it, creating a new one if need be.  If there
334:     is no service table from the file, this static variable
335:     holds the head of the service_library list made from the
336:     default configuration.  */
337: ? ? ? static name_database default_table;
338: ? ? ? ni->library = nss_new_service (service_table ?: &default_table,
339:                 ? ? ni->name); //若ni->library的值為NULL,那么就會(huì)新建一個(gè)ni->library并將成員都進(jìn)行初始化
340: ? ? ? if (ni->library == NULL)
341:    return -1;
342: ? ? }
343: 
344: ? if (ni->library->lib_handle == NULL) //由于ni->library剛新建,因此ni->library->lib_handle必定為NULL
345: ? ? {
346: ? ? ? /* Load the shared library.  */
347: ? ? ? size_t shlen = (7 + strlen (ni->name) + 3
348:         ? ? ?+ strlen (__nss_shlib_revision) + 1);
349: ? ? ? int saved_errno = errno;
350: ? ? ? char shlib_name[shlen];
351: 
352: ? ? ? /* Construct shared object name.  */
353: ? ? ? __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
354:                     ? ? ?"libnss_"),
355:                 ? ?ni->name),
356:             ?".so"), //shalib_name是根據(jù)拼接得到
357:        __nss_shlib_revision);
358: 
359: ? ? ? ni->library->lib_handle = __libc_dlopen (shlib_name); //加載動(dòng)態(tài)鏈接庫(kù)
?

上述代碼有個(gè)非常關(guān)鍵的點(diǎn)在于,程序會(huì)使用__libc_dlopen打開(kāi)shalib_name指定的動(dòng)態(tài)鏈接庫(kù),而shalib_name是通過(guò)ni->name進(jìn)行一系列的拼接得到,而ni->name則是存放在結(jié)構(gòu)體service_user *ni中的,該結(jié)構(gòu)體又是存放在堆內(nèi)存中的。那么我們就找到了關(guān)鍵的值ni->name,它是能夠完成修改程序執(zhí)行流程的關(guān)鍵變量。

舉個(gè)例子,例如我們將ni->name修改為X/test,那么最后拼接的結(jié)果會(huì)得到libnss_X/test.so,那么如果我們?cè)诋?dāng)前目錄下新建一個(gè)libnss_X并且在該目錄中創(chuàng)建一個(gè)test.so的動(dòng)態(tài)鏈接庫(kù),那么sudo就會(huì)加載并執(zhí)行我們動(dòng)態(tài)鏈接庫(kù)中的代碼。至此我們找到利用的第一個(gè)關(guān)鍵因素,可利用堆塊。

布置堆塊的操作

由于我們已經(jīng)找到了可利用的堆塊,如果能夠?qū)⒍岩绯龅亩褖K部署在可利用堆塊的上方,在利用堆溢出修改ni->name,即可完成任意代碼執(zhí)行的效果。

在sudo的main函數(shù)中,會(huì)執(zhí)行setlocate函數(shù)。setlocale 是一個(gè)用于設(shè)置程序的區(qū)域設(shè)置(locale)的函數(shù),在許多編程語(yǔ)言和操作系統(tǒng)中都有對(duì)應(yīng)的實(shí)現(xiàn)。

區(qū)域設(shè)置是指程序在運(yùn)行時(shí)所采用的語(yǔ)言、地區(qū)、日期格式、貨幣符號(hào)等相關(guān)信息的集合。通過(guò)設(shè)置區(qū)域設(shè)置,程序可以根據(jù)不同的地區(qū)和語(yǔ)言環(huán)境來(lái)適應(yīng)本地化需求。

export LC_ALL=en_US.UTF-8@XXXX

而在setlocal函數(shù)中涉及十分多的堆塊分配與釋放的操作,當(dāng)調(diào)用setlocal(LC_ALL,"")時(shí),程序會(huì)通過(guò)環(huán)境變量設(shè)置的值去搜索區(qū)域設(shè)置的值,而環(huán)境變量的搜索則依靠_nl_find_locale函數(shù)。

_nl_find_locale函數(shù)
File: locale\findlocale.c
101: struct __locale_data *
102: _nl_find_locale (const char *locale_path, size_t locale_path_len,
103:         int category, const char **name)
104: {
 ?      ... 
184: ? /* LOCALE can consist of up to four recognized parts for the XPG syntax:
185: 
186:        language[_territory[.codeset]][@modifier]
187: 
188: ? ?  Beside the first all of them are allowed to be missing.  If the
189: ? ?  full specified locale is not found, the less specific one are
190: ? ?  looked for.  The various part will be stripped off according to
191: ? ?  the following order:
192:        (1) codeset
193:        (2) normalized codeset
194:        (3) territory
195:        (4) modifier
196: ?  */
 ? ? ? /*
 ? ? ?      區(qū)域的格式為C_en_US.UTF-8@XXXXXX
 ? ? ?      _nl_explode_name用于判斷(1)(2)(3)(4)哪部分存在,哪部分缺失
 ? ? ? */
197: ? mask = _nl_explode_name (loc_name, &language, &modifier, &territory,
198:             ? &codeset, &normalized_codeset);
199: ? if (mask == -1)
200: ? ? /* Memory allocate problem.  */
201: ? ? return NULL;
202: 
 ?      //locale_file則給區(qū)域設(shè)置進(jìn)行動(dòng)態(tài)內(nèi)存的分配
205: ? locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
206:                 ? ?locale_path, locale_path_len, mask,
207:                 ? ?language, territory, codeset,
208:                 ? ?normalized_codeset, modifier,
209:                 ? ?_nl_category_names_get (category), 0); //返回NULL
210: 
211: ? if (locale_file == NULL)
212: ? ? {
213: ? ? ? /* Find status record for addressed locale file.  We have to search
214:     through all directories in the locale path.  */
215: ? ? ? locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
216:                    locale_path, locale_path_len, mask,
217:                    language, territory, codeset,
218:                    normalized_codeset, modifier,
219:                    _nl_category_names_get (category), 1);
220: ? ? ? if (locale_file == NULL)
221:    /* This means we are out of core.  */
222:    return NULL;
223: ? ? }
}

_nl_make_l10nflist**函數(shù)**

_nl_make_l10nflist會(huì)根據(jù)我們傳入的值進(jìn)行堆塊的分配。

File: intl\l10nflist.c
150: struct loaded_l10nfile *
151: _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list,
152:         ? ?const char *dirlist, size_t dirlist_len,
153:         ? ?int mask, const char *language, const char *territory,
154:         ? ?const char *codeset, const char *normalized_codeset,
155:         ? ?const char *modifier,
156:         ? ?const char *filename, int do_allocate)
157: {
 ?      ...
165: ? //根據(jù)我們傳入的區(qū)域值的長(zhǎng)度進(jìn)行動(dòng)態(tài)分配
166: ? abs_filename = (char *) malloc (dirlist_len
167:                 ?+ strlen (language)
168:                 ?+ ((mask & XPG_TERRITORY) != 0
169:                 ? ? ? strlen (territory) + 1 : 0)
170:                 ?+ ((mask & XPG_CODESET) != 0
171:                 ? ? ? strlen (codeset) + 1 : 0)
172:                 ?+ ((mask & XPG_NORM_CODESET) != 0
173:                 ? ? ? strlen (normalized_codeset) + 1 : 0)
174:                 ?+ ((mask & XPG_MODIFIER) != 0
175:                 ? ? ? strlen (modifier) + 1 : 0)
176:                 ?+ 1 + strlen (filename) + 1);
177: 
 ?      ...
292: }
?

setlocale**函數(shù)**

setlocale函數(shù)總體操作則是讀取環(huán)境變量的值獲取區(qū)域設(shè)置的值,根據(jù)區(qū)域設(shè)置的值分配堆塊大小,若其中存在不符合區(qū)域值的規(guī)范,則會(huì)將所有先前申請(qǐng)的堆塊都釋放掉。

File: locale\setlocale.c
334: ? ? ? while (category-- > 0)
335:    if (category != LC_ALL)
336:      {
 ?          //通過(guò)_nl_find_locale函數(shù)去獲取環(huán)境變量的值,存放在newdata[category]中
337:     ? ?newdata[category] = _nl_find_locale (locale_path, locale_path_len,
338:                         category,
339:                         &newnames[category]);
340: 
            ...
364:        else
365:          {
 ?              //使用__strdup函數(shù)在堆內(nèi)存中分配空間,并將newdata[category]拷貝進(jìn)去
366:         ? ?newnames[category] = __strdup (newnames[category]);
367:         ? ?if (newnames[category] == NULL)
368:         ? ? ?break;
369:          }
 ?          ...
393:     ?if (category != LC_ALL && newnames[category] != _nl_C_name
394:     ? ? ?&& newnames[category] != _nl_global_locale.__names[category])
395:     ? ?free ((char *) newnames[category]); //這里就是堆塊釋放的原語(yǔ)了,只要有一個(gè)區(qū)域設(shè)置的值不符合規(guī)范,則將之前所有申請(qǐng)的堆塊都釋放掉
?

因此可以通過(guò)區(qū)域值去控制堆塊的大小,接著在最后設(shè)置一個(gè)錯(cuò)誤的區(qū)域值去控制堆塊的位置,至此我們找到可控制堆塊的操作。

LC_IDENTIFICATION = C.UTF-8@XX..XX #若長(zhǎng)度為0x10,則malloc(0x10) LC_MEASUREMENT = C.UTF-8@XX..XXX,#若長(zhǎng)度為0X20,則malloc(0x20) LC_TELEPHONE = XXXX #不符合區(qū)域值的規(guī)范,則會(huì)調(diào)用free()

exp的分析

由于我們需要控制server_user的堆塊,因此需要知道該堆塊的大小為多少,通過(guò)調(diào)試可知是0x40的堆塊,因此利用setlocate多釋放幾個(gè)0x40的堆塊,那么server_user就會(huì)使用到我們所釋放的堆塊。

緊接著將漏洞堆塊分配到server_user堆塊的上方,由于server_user的堆塊是我們自己構(gòu)建的,因此只需要在釋放該堆塊的同時(shí)也釋放漏洞堆塊即可,并且漏洞堆塊的申請(qǐng)可是根據(jù)參數(shù)的長(zhǎng)度所設(shè)置的

將設(shè)置區(qū)域值的函數(shù)設(shè)置為堆塊分配與釋放的原語(yǔ),使用@后面的字符控制堆塊的大小

?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-505206.html

使用錯(cuò)誤的區(qū)域值進(jìn)行堆塊的釋放

最后就是如何填充到可利用堆塊,這里使用堆溢出,并且在環(huán)境變量中構(gòu)造填充字符串,使得漏洞堆塊可以覆蓋掉可利用堆塊的內(nèi)容值,但這里需要注意的是,我們需要將ni->library中用\x00填充,而\x00是無(wú)法直接輸入到環(huán)境變量中的,因此需要再次觀察漏洞函數(shù)是如何拷貝字符的。根據(jù)代碼分析可知,只要''后緊跟著'\x00',那么我們就能將\x00的值直接拷貝的堆內(nèi)存中。緊接著將ni->name修改為我們認(rèn)為構(gòu)造的動(dòng)態(tài)鏈接庫(kù)即可。

File: plugins\sudoers\sudoers.c
866:            if (from[0] == '\\' && !isspace((unsigned char)from[1])) //若 '\' 后跟著'\x00'
867:             ? ?from++; //此時(shí)from會(huì)指向\x00
868:            *to++ = *from++; //使用\x00進(jìn)行值的拷貝
869:         ?  }

設(shè)置多個(gè)環(huán)境變量使得內(nèi)存存在多個(gè)'' + '\x00',從而使用'\x00'去覆蓋堆的內(nèi)存值。

演示效果如下

漏洞修復(fù)

漏洞的修復(fù)則是將MODE_EDIT的標(biāo)志位進(jìn)行了額外的判斷,并且在''后面增加了對(duì)'\0'的校驗(yàn)

?
--- a/plugins/sudoers/sudoers.c Sat Jan 23 08:43:59 2021 -0700
+++ b/plugins/sudoers/sudoers.c Sat Jan 23 08:43:59 2021 -0700
@@ -547,7 +547,7 @@
 
 ? ? /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
 ? ? /* XXX - causes confusion when root is not listed in sudoers */
- ? ?if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
+ ? ?if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT) && prev_user != NULL) {
    if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
     ? ?struct passwd *pw;
 
@@ -932,8 +932,8 @@
 ? ? if (user_cmnd == NULL)
    user_cmnd = NewArgv[0];
 
- ? ?if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
-   if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
+ ? ?if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT|MODE_CHECK)) {
+   if (!ISSET(sudo_mode, MODE_EDIT)) { //對(duì)MODE_EDIT進(jìn)行了額外的判斷
     ? ?const char *runchroot = user_runchroot;
     ? ?if (runchroot == NULL && def_runchroot != NULL &&
         ? ?strcmp(def_runchroot, "*") != 0)
@@ -961,7 +961,8 @@
        sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
        debug_return_int(NOT_FOUND_ERROR);
     ?  }
-    ? ?if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
+    ? ?if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) &&
+        ? ?ISSET(sudo_mode, MODE_RUN)) { //需要sudo -s才能進(jìn)行轉(zhuǎn)義
        /*
         * When running a command via a shell, the sudo front-end
         * escapes potential meta chars.  We unescape non-spaces
@@ -969,10 +970,22 @@
         */
        for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
         ? ?while (*from) {
-           if (from[0] == '\\' && !isspace((unsigned char)from[1]))
+           if (from[0] == '\\' && from[1] != '\0' && ?//增加了'\0'的判斷
+               !isspace((unsigned char)from[1])) {
             ? ?from++;
+           }
+           if (size - (to - user_args) < 1) {
+            ? ?sudo_warnx(U_("internal error, %s overflow"),
+               __func__);
+            ? ?debug_return_int(NOT_FOUND_ERROR);
+           }
            *to++ = *from++;
         ?  }
+        ? ?if (size - (to - user_args) < 1) {
+           sudo_warnx(U_("internal error, %s overflow"),
+            ? ?__func__);
+           debug_return_int(NOT_FOUND_ERROR);
+        ?  }
         ? ?*to++ = ' ';
        }
        *--to = '\0';

總結(jié)

Sudo堆溢出攻擊流程

首先利用setlocate作為堆塊分配與釋放的原語(yǔ),構(gòu)造出適合的堆布局確保server_user堆塊盡可能貼近漏洞代碼開(kāi)辟出來(lái)的堆塊。

其次利用堆溢出將server_user堆塊的ni->name值覆蓋,覆蓋的值為惡意構(gòu)造的動(dòng)態(tài)鏈接庫(kù)名。

最后等待動(dòng)態(tài)鏈接庫(kù)被加載執(zhí)行。

Sudo堆溢出利用的限制

由于sudo堆溢出依賴堆的布局,因此不同版本的sudo或者操作系統(tǒng)都會(huì)影響漏洞的利用。

更多網(wǎng)安技能的在線實(shí)操練習(xí),請(qǐng)點(diǎn)擊這里>>

?

到了這里,關(guān)于Sudo堆溢出漏洞(CVE-2021-3156)復(fù)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • VMware ESXi OpenSLP 堆溢出漏洞(CVE-2021–21974)勒索事件

    VMware ESXi OpenSLP 堆溢出漏洞(CVE-2021–21974)勒索事件

    據(jù)BleepingComputer 2月3日消息,法國(guó)計(jì)算機(jī)緊急響應(yīng)小組(CERT-FR) 近日發(fā)出警告,攻擊者正通過(guò)一個(gè)遠(yuǎn)程代碼執(zhí)行漏洞,對(duì)全球多地未打補(bǔ)丁的 VMware ESXi 服務(wù)器部署新型ESXiArgs 勒索軟件。 據(jù)悉,該漏洞編號(hào)為CVE-2021-21974,由 OpenSLP 服務(wù)中的堆溢出問(wèn)題引起,未經(jīng)身份驗(yàn)證的攻擊者

    2024年02月04日
    瀏覽(16)
  • CVE-2021-22205 GitLab 遠(yuǎn)程命令執(zhí)行漏洞復(fù)現(xiàn)

    CVE-2021-22205 GitLab 遠(yuǎn)程命令執(zhí)行漏洞復(fù)現(xiàn)

    目錄 一、漏洞信息 二、環(huán)境搭建 三、復(fù)現(xiàn)過(guò)程 1.測(cè)試漏洞 2.漏洞利用,反彈shell 四、修復(fù)建議 一、漏洞信息 漏洞名稱 GITLAB 遠(yuǎn)程命令執(zhí)行漏洞 漏洞編號(hào) CVE-2021-22205 危害等級(jí) 高危 CVSS評(píng)分 6.5 漏洞廠商 Ruby 受影響版本 11.9 = Gitlab CE/EE 13.8.8;13.9 = Gitlab CE/EE 13.9.6;13.10 = Gitlab

    2024年02月05日
    瀏覽(26)
  • HIKVISION??低暣a執(zhí)行漏洞復(fù)現(xiàn)(CVE-2021-36260)

    HIKVISION??低暣a執(zhí)行漏洞復(fù)現(xiàn)(CVE-2021-36260)

    2023年將會(huì)持續(xù)于B站、CSDN等各大平臺(tái)更新,可加入粉絲群與博主交流:838681355,為了老板大G共同努力。 GET訪問(wèn)/x.asp

    2024年02月12日
    瀏覽(21)
  • Django系列所有漏洞復(fù)現(xiàn)vulhubCVE-2018-14574,CVE-2022-34265,CVE-2021-35042

    Django系列所有漏洞復(fù)現(xiàn)vulhubCVE-2018-14574,CVE-2022-34265,CVE-2021-35042

    Django默認(rèn)配置下,如果匹配上的URL路由中最后一位是/,而用戶訪問(wèn)的時(shí)候沒(méi)加/,Django默認(rèn)會(huì)跳轉(zhuǎn)到帶/的請(qǐng)求中。(由配置項(xiàng)中的django.middleware.common.CommonMiddleware、APPEND_SLASH來(lái)決定)。 在path開(kāi)頭為//example.com的情況下,Django沒(méi)做處理,導(dǎo)致瀏覽器認(rèn)為目的地址是絕對(duì)路徑,最

    2024年02月07日
    瀏覽(20)
  • CVE-2021-1675 Windows Print Spooler權(quán)限提升漏洞復(fù)現(xiàn)

    CVE-2021-1675 Windows Print Spooler權(quán)限提升漏洞復(fù)現(xiàn)

    Microsoft Windows Print Spooler 服務(wù)未能限制對(duì)RpcAddPrinterDriverEx()函數(shù)的訪問(wèn),該函數(shù)可能允許遠(yuǎn)程身份驗(yàn)證的攻擊者以系統(tǒng)權(quán)限在易受攻擊的系統(tǒng)上執(zhí)行任意代碼。該RpcAddPrinterDriverEx()函數(shù)用于在系統(tǒng)上安裝打印機(jī)驅(qū)動(dòng)程序。此函數(shù)的參數(shù)之一是DRIVER_CONTAINER對(duì)象,它包含有關(guān)添加的

    2024年02月06日
    瀏覽(24)
  • WebLogic反序列化漏洞復(fù)現(xiàn)+利用工具(CVE-2021-2394)

    WebLogic反序列化漏洞復(fù)現(xiàn)+利用工具(CVE-2021-2394)

    Oracle官方發(fā)布了2021年7月份安全更新通告,通告中披露了WebLogic組件存在高危漏洞,攻擊者可以在未授權(quán)的情況下通過(guò)IIOP、T3協(xié)議對(duì)存在漏洞的WebLogic Server組件進(jìn)行攻擊。成功利用該漏洞的攻擊者可以接管WebLogic Server。 這是一個(gè)二次反序列化漏洞,是CVE-2020-14756和CVE-2020-14825的

    2024年02月06日
    瀏覽(37)
  • Apache Http Server 路徑穿越漏洞復(fù)現(xiàn)(CVE-2021-41773)

    Apache Http Server 路徑穿越漏洞復(fù)現(xiàn)(CVE-2021-41773)

    Apache HTTP Server(簡(jiǎn)稱 Apache)是 Apache 軟件基金會(huì)的一個(gè)開(kāi)放源碼的網(wǎng)頁(yè)服務(wù)器軟件,可以在大多數(shù)電腦操作系統(tǒng)中運(yùn)行。由于其跨平臺(tái)和安全性,被廣泛使用,是最流行的 Web 服務(wù)器軟件之一。它快速、可靠并且可通過(guò)簡(jiǎn)單的 API 擴(kuò)展,將 Perl/Python 等解釋器編譯到服務(wù)器中。

    2024年02月08日
    瀏覽(46)
  • 【漏洞復(fù)現(xiàn)】Apache_HTTP_2.4.50_路徑穿越漏洞(CVE-2021-42013)

    【漏洞復(fù)現(xiàn)】Apache_HTTP_2.4.50_路徑穿越漏洞(CVE-2021-42013)

    感謝互聯(lián)網(wǎng)提供分享知識(shí)與智慧,在法治的社會(huì)里,請(qǐng)遵守有關(guān)法律法規(guī) 說(shuō)明 內(nèi)容 漏洞編號(hào) CVE-2021-42013 漏洞名稱 Apache HTTP_2.4.50_路徑穿越漏洞 漏洞評(píng)級(jí) 高危 影響范圍 2.4.49 2.4.50 漏洞描述 CVE-2021-42013是由CVE-2021-41773的不完整修復(fù)導(dǎo)致的漏洞,攻擊者可以使用路徑遍歷攻擊將

    2024年02月05日
    瀏覽(18)
  • MS08-067遠(yuǎn)程代碼執(zhí)行漏洞(CVE-2008-4250) | Windows Server服務(wù)RPC請(qǐng)求緩沖區(qū)溢出漏洞復(fù)現(xiàn)

    MS08-067遠(yuǎn)程代碼執(zhí)行漏洞(CVE-2008-4250) | Windows Server服務(wù)RPC請(qǐng)求緩沖區(qū)溢出漏洞復(fù)現(xiàn)

    What is SMB? SMB(Server Message Block)是一個(gè)協(xié)議服務(wù)器信息塊,它是一種客戶機(jī)/服務(wù)器、請(qǐng)求/響應(yīng)協(xié)議,通過(guò)SMB協(xié)議可以在計(jì)算機(jī)間共享文件、打印機(jī)、命名管道等資源,電腦上的網(wǎng)上鄰居就是靠SMB實(shí)現(xiàn)的;SMB協(xié)議工作在應(yīng)用層和會(huì)話層,可以用在TCP/IP協(xié)議之上,SMB使用TCP139端口和

    2024年02月08日
    瀏覽(20)
  • Log4j2 - JNDI 注入漏洞復(fù)現(xiàn)(CVE-2021-44228)

    Log4j2 - JNDI 注入漏洞復(fù)現(xiàn)(CVE-2021-44228)

    Apache log4j 是 Apache 的一個(gè)開(kāi)源項(xiàng)目, Apache log4j2 是一個(gè) Java 的日志記錄工具。該工具重寫了 log4j 框架,并且引入了大量豐富的特性。我們可以控制日志信息輸送的目的地為控制臺(tái)、文件、GUI組件等,通過(guò)定義每一條日志信息的級(jí)別,能夠更加細(xì)致地控制日志的生成過(guò)程。 l

    2024年02月07日
    瀏覽(35)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包