Exploit of SUDO vulnerability Heap-Based Overflow [CVE-2021-3156 ]
CVE-2021-3156 is a Heap-Based-Buffer overflow in sudo, in this blog I will share my walkthrough of this CVE and my final exploit for it, let's start with POC.
First, I used AddressSanitizer(ASan) which is used to detect memory access errors such as use-after-free and memory leaks this is a sample output of it, and we can see the file which cause the crash with the line number
and this is the command used to compile sudo with ASanWe can check the root cause of the crash in gdb by passing the payload and breakpoint on line number 868 in file sudoers.cif we used the next instruction(ni) to follow the code and we can see when we reach the backslash(\) the code is passing the next value after it but our backslash is at the end of the string so what it will be passed? yes, it will be the Null Byte that is used to end the string, what do you think will happen if we do not have the end of our string? it will continue writing into the allocated memory and overflow it.
The vulnerable code with better view
to reach the above vulnerable code we have to pass some conditions, the following screenshot shows the first condition
this screenshot shows the second condition
to reach the first condition we have to use (-edit) any word that should end with (edit) so we can use (sudoedit) which will set MODE_EDIT
so now we have to fuzz onto sudo the idea is simple we will generate random values with random size, and we will pass these values to ENV variables and sudo arguments and if we have a crash we will pass this crash to gdb and save the backtrace and the name of crashed function into the output file (doing it is not easy 😂) so the great playlist from LiveOverflow about the same CVE was useful
this file includes the backtrace of the crash
let's try arguments to cause the crash and see, the first file is a Python file which will pass the arguments to the next file which is (test.c) the following screenshot shows the file with arguments but there is a missing line which it will be
args = ["./test"] + argos.execv("./test", args)
the (test.c) file is taking the arguments and pass it to the (sudoedit) binary but why we used this method? if we try to pass the backslashes as ENV variables it will be parsed as one ENV variable but if we used this method by passing the args to the test binary it will be parsed as the way we want (which is each backslash individual)
Code Time
I could know the glibc version by running (ldd --version) it is 2.31, I used bootlin elixir to check the code of this version of glibc
nss_load_library has some interesting thing which is this part use (dlopen) in line 359 which load an external library using the name and if check line 353 it creates a name of the shared library and passes it to (dlopen) to include it with this format (libnss_<name_from_ni>.so.<version> (i.e libnss_flex.so.2)) you can read the man page of dlopen
If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname
Exploit Time
We modified the arguments a bit, and we added the name of the lib we want to include with "/" (note that) after adding the padding to reach the vulnerable code we used some backslashes which replace the NULL bytes (we can not use null bytes remember that) we set (ni->next) & (ni->library) to (0x00) this will reach the condition from (nss_load_libbrary) which will call (nss_new_service) to create & set (lib_handle) to NULL and using that we will reach the second condition will will load library with our controlled name
let's write the library and convert the Python code into C and write our shared library.
Coding
we have 4 files for our exploit
- flex.c : shared library which we will load
- exploit.c : include the arguments(payload) which will be passed to (root) file
- root.c : will take the arguments(payload) from (exploit) file and pass it to (sudoedit)
- run.sh : bash file to compile the C files and run the exploit
the following screenshots show the above files with their contents
Comments
Post a Comment