Heap-Based Buffer Overflow in Sudo
Last Update:
Word Count:
Read Time:
CVE-2021-3156: Heap-Based Buffer Overflow in Sudo
Intro
This CVE almost impact on all distributions of linux, every common user can use this vulnerability escaped permission as root. Disclosured at 2021-01-13. We have a ctf match (hws) at 2021-02, there is a pwn challenge can use this vulnerability to escape permission as root, but I don’t use this CVE to realize it. Just use CVE-2019-14287 easily to get root. At that time, I knew this CVE, but I didn’t want explore the background technologes. Now, this paper will analyse this vulnerability and let’s to exploit it.
What versions are vulnerable?
The following versions of sudo are vulnerable:
- All legacy versions from 1.8.2 to 1.8.31p2
- All stable versions from 1.9.0 to 1.9.5p1
sudo official website: https://www.sudo.ws/
Check if you are affected
Login as non-root user
Method 1
Run a command as follow to check.
1 |
|
If you receive a usage or error message, sudo is not vulnerable. If the result is a Segmentation fault, sudo is vulnerable. As you can see below:
1 |
|
Method 2
Coming from official judge method (Not recommend!)
Run command sudoedit -s /
If the system is vulnerable, it will response with an error that starts with “sudoedit”
If the system is not vulnerable, it will response with an error that starts with “usage”
1 |
|
But I try it, this dosen’t work, I cannot use this method to judge if my system is vulnerable. becuase I test on my latest sudo, this version has been patched, I use this method to test,the result is correct. when I test on my vulnerable system. it dosen’t show “sudoedit”, instead let me input password. So I recommend tester to use method 1 to test your linux system.
Prepare ENV
My sudo version and operation system version information as follows.
1 |
|
My vulnerable system is ubuntu 18.04.1 and operation system is ubuntu~18.04.1
I test version is 1.8.21p2. We should download source code to analyse this vulnerability. You can download source code of 1.8.21p2 version here.
If we downloaded source code, we can open NEWS file learn historic vulnerabilities : ). There are so many bug we can learn. Nice!!!
Now we must to dynamic debugging sudo program, some tools we will used.
gdb + pwndbg plugin — Debugging sudo program
gcc — Compile our C exploit script to ELF binary
If your prepared tools above, now starting our journey. Last set your linux system sudo program version as 1.8.21p2.
install step
1 |
|
Hole Technical Analysis
This vulnerability is discovered by fuzz, So we have to explore how is it crashed. sudo
allows users to run programs with the security previleges of another user. sudoedit
is a built-in command of sudo that allows users to securely edit files. In this new fulnerability, Qualys researchers discovered that when running sudoedit
whth flags -s or -i, the command will not result exit with an error, and the sudoers policy plugin will not remove the escape characters, resulting instead in reading beyond the last of a string. if it ends with an un-escaped backslash character. May allow attackers to exploit this vulnerability in order to run arbitrary code execution with root privilege without authentication.
Test what arguments in running programs
1 |
|
outputs:
1 |
|
1 |
|
outputs:
1 |
|
So arguments is AAAAAAAAA\
This version, if sudo
is executed to run a command in shell mode
. through the -s
option
or through -i option sets sudo’s MODE_SHELL
and MODE_LOGIN_SHELL
flags.
parse_args
function used for parse program arguments
src/sudo.c: 193 in main() function
1 |
|
if we set flags as MODE_SHELL, we can enter shell mode, that can rewrite argv.
By concatenating all command-line arguments and by escaping all meta-characters with backslashes
src/parse_args.c : 528 in parse_args() function
1 |
|
Now we debugging this sudoedit program, copy this file to current directory from /usr/bin/sudoedit, use IDA or Cutter to analyse it.
I use IDA 7.5 to decompile it, we should find parse_args function. because this program haven’t parse_args function symbol, I have to find this parse_args function by self according main argc arguments.
1 |
|
Because v2 is main function argc argument, so I easily found sub_11760, it is parse_args function.
Found above source’s pseudo code as follow.
1 |
|
We just to know address of this part for debugging.
show asm
1 |
|
The parse_args function offset is 0x11760
0x11760-> 0x118B0 -> 0x5674
Now we can set breakpoint at ELF_BASE_ADDRESS + 0x11760 ( parse_args ) to debugging sudoedit program.
When I debugging, I don’t know why this program haven’t enter above code.
Continue to read blog @_@ …
The author say: In sudoders_policy_main(), set_cmnd() concatenates the command-line arguements into a heap-based buffer. user_args and unescapes the meta-characters (for sudoers matching and logging purposes). These functions are at plugins/sudoers/sudoers.c.
plugins/sudoers/sudoers.c in set_cmnd() function
1 |
|
If a command-line argument ends with a signle backslash character, then form[0]
is a backslash character, and form[1]
is ‘\x00’ (is not space character)
form
is incremented and points to the null terminator (‘\x00’);
The null terminator is copied to the user_args
buffer, the form
is incremented again and points to the first character after the null terminator. (out of arguments’ bounds). The whill loop reads and copies out of bounds characters to the user_args
buffer.
So, In the words, set_cmnd is a vulnerable function. There is a heap-based buffer overflow vulnerability.
That copy out of bounds data to the user_args
buffer, and not sure how much copied it is. when we exploit, we can use ‘\00’ to terminate coping.
Now how we trigger this vulnerability?
1 |
|
we should set sudo_mode as MODE_SHELL
and MODE_LOGIN_SHELL
It is necessary condition for reaching the vulnerable code. parse_args function can do that, but this function already escaped all meta-characters (i.e., it escaped every single backslash with a second backslash). so including more backslashes, that cannot trigger vuln.
Found a loophole:
if we execute sudo
as sudoedit
instead of sudo
, then parse_args() automatically sets sudo_mode as MODE_EDIT, but does not reset valid_flags
, and the valid_flags
include MODE_SHELL
by default.
If we execute sudoedit -s
, then we set both MODE_EDIT
and MODE_SHELL
(but not MODE_RUN), we avoid the escape code, reach the vulnerable code, and overflow the heap-based buffer user_args
through a command-line argument that ends with a single backslash character.
Testing heap overflow, we use gdb to test it.
How to exploit?
gdb.sh
1 |
|
Run gdb.sh
1 |
|
Input run, heap in gdb program
1 |
|
Show memory.
1 |
|
It is obviously, this is a heap overflow at top chunk, has overlaped the top chunk.
How can we get shell?
Updating…
ref: https://github.com/blasty/CVE-2021-3156
ref: https://github.com/reverse-ex/CVE-2021-3156/blob/main/info