Introduction
In this blog post, we dive into the intricacies of the Sudo Heap Overflow Vulnerability (CVE-2021-3156). On January 26, 2021, Qualys Research Labs discovered a flaw in sudo. When sudo parses the command line parameters, the truncation character is wrongly judged, which leads to the attacker maliciously constructing a payload, causing sudo to overflow the heap. This vulnerability can cause Local privilege escalation.
Environment
environment version
• ubuntu 20.04
• sudo-1.8.31p2
Use the following command to compile and install
cd ./sudo-SUDO_1_8_31p2 mkdir build ./configure --prefix = /home/pwn/sudo CFLAGS = "-O0 -g " make && make install
Vulnerability
#poc
./sudoedit -s '\' 11111111111111111111111111111111111111111111111111111111111111
Executing the above POC and executing sudoedit will display the words malloc(): invalid size, which is a typical exception caused by a heap overflow.
Vulnerability Analysis
The Source code analysis
set_cmnd function
File : plugins\sudoers\sudoers . c
800 : static int
801 : set_cmnd ( void )
802 : { ... 819 : if ( sudo_mode & ( MODE_RUN | MODE_EDIT | MODE_CHECK )) { //Need to meet the setting of the flag bit To enter the escape process ... 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 ++ ) //Traverse each parameter
853 : size += strlen ( * av ) + 1 ; // Calculate the length of each parameter
854 : if ( size == 0 || ( user_args = malloc ( size )) == NULL ) { // Dynamically allocate a section of memory through malloc to store parameter content
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 )) { //The setting of the flag bit needs to be satisfied to enter the escape process
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 ++ ) { //Traverse each environment variable and copy the content to the memory
865 : while ( * from ) { /*
The vulnerability point, when scanning the parameter content, encounter \ needs to be escaped, such as '\t' , '\n', etc., so sudo only judges whether \ is followed by a space character, that is, the isspace function is used to judge . characters included in isspace are as follows: ' ' (0x20) space (SPC) space character '\t' (0x09) horizontal tab (TAB) horizontal tab character '\n' (0x0a) newline ( LF) newline character '\v' (0x0b) vertical tab (VT ) vertical tab character '\f' (0x0c) feed (FF) form feed character '\r' (0x0d) carriage return (CR) does not include '' above carriage return . The parameters are separated by '', so when '\' is followed by '', from++ will cause the next parameter to be copied in,and finally cause the heap block to overflow.*/ 866 :
== '\\' && ! isspace (( unsigned char ) from [ 1 ]))
867 : from ++ ;
868 : * to ++ = * from ++ ;
869 : }
870 : * to ++ = ' ' ;
871 : }
872 : *-- to = '' ;
Therefore, the vulnerability lies in the need to escape the escape character when entering the set_cmnd function, but the function does not judge the escape character as the end of the parameter, that is, \ + \x00
parse_args function
The parse_args function is used to reverse escaping, that is, if there are escape characters in the parameter, a \ will be added before each escape character
File : src\parse_args . c
592 : if ( ISSET ( mode , MODE_RUN ) && ISSET ( flags , MODE_SHELL )) { //The setting of the flag bit needs to be satisfied before entering the reverse escape process
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